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 /* --set-label: New object label. */
83 static char *set_label;
85 /* Number of warnings issued. */
86 static size_t n_warnings;
88 static void usage (void);
89 static void parse_options (int argc, char **argv);
92 dump_item (const struct spv_item *item)
94 if (show_member_names && (item->xml_member || item->bin_member))
96 const char *x = item->xml_member;
97 const char *b = item->bin_member;
99 /* The strings below are not marked for translation because they are only
100 useful to developers. */
102 ? xasprintf ("%s and %s:", x, b)
103 : xasprintf ("%s:", x ? x : b));
104 text_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s,
105 xstrdup ("Member Names")));
108 switch (spv_item_get_type (item))
110 case SPV_ITEM_HEADING:
114 spv_text_submit (item);
118 pivot_table_submit (pivot_table_ref (spv_item_get_table (item)));
127 case SPV_ITEM_OBJECT:
139 print_item_directory (const struct spv_item *item)
141 for (int i = 1; i < spv_item_get_level (item); i++)
144 enum spv_item_type type = spv_item_get_type (item);
145 printf ("- %s", spv_item_type_to_string (type));
147 const char *label = spv_item_get_label (item);
149 printf (" \"%s\"", label);
151 if (type == SPV_ITEM_TABLE)
153 const struct pivot_table *table = spv_item_get_table (item);
154 char *title = pivot_value_to_string (table->title,
155 SETTINGS_VALUE_SHOW_DEFAULT,
156 SETTINGS_VALUE_SHOW_DEFAULT);
157 if (!label || strcmp (title, label))
158 printf (" title \"%s\"", title);
162 const char *command_id = spv_item_get_command_id (item);
164 printf (" command \"%s\"", command_id);
166 const char *subtype = spv_item_get_subtype (item);
167 if (subtype && (!label || strcmp (label, subtype)))
168 printf (" subtype \"%s\"", subtype);
170 if (!spv_item_is_visible (item))
171 printf (" (hidden)");
172 if (show_member_names && (item->xml_member || item->bin_member))
174 if (item->xml_member && item->bin_member)
175 printf (" in %s and %s", item->xml_member, item->bin_member);
176 else if (item->xml_member)
177 printf (" in %s", item->xml_member);
178 else if (item->bin_member)
179 printf (" in %s", item->bin_member);
185 run_detect (int argc UNUSED, char **argv)
187 char *err = spv_detect (argv[1]);
189 error (1, 0, "%s", err);
193 run_directory (int argc UNUSED, char **argv)
195 struct spv_reader *spv;
196 char *err = spv_open (argv[1], &spv);
198 error (1, 0, "%s", err);
200 struct spv_item **items;
202 spv_select (spv, criteria, n_criteria, &items, &n_items);
203 for (size_t i = 0; i < n_items; i++)
204 print_item_directory (items[i]);
212 const struct spv_item **nodes;
216 const struct spv_item *stub[N_STUB];
220 swap_nodes (const struct spv_item **a, const struct spv_item **b)
222 const struct spv_item *tmp = *a;
228 get_path (const struct spv_item *item, struct item_path *path)
230 size_t allocated = 10;
231 path->nodes = path->stub;
236 if (path->n >= allocated)
238 if (path->nodes == path->stub)
239 path->nodes = xmemdup (path->stub, sizeof path->stub);
240 path->nodes = x2nrealloc (path->nodes, &allocated,
241 sizeof *path->nodes);
243 path->nodes[path->n++] = item;
247 for (size_t i = 0; i < path->n / 2; i++)
248 swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]);
252 free_path (struct item_path *path)
254 if (path && path->nodes != path->stub)
259 dump_heading_transition (const struct spv_item *old,
260 const struct spv_item *new)
265 struct item_path old_path, new_path;
266 get_path (old, &old_path);
267 get_path (new, &new_path);
270 for (; common < old_path.n && common < new_path.n; common++)
271 if (old_path.nodes[common] != new_path.nodes[common])
274 for (size_t i = common; i < old_path.n; i++)
275 group_close_item_submit (group_close_item_create ());
276 for (size_t i = common; i < new_path.n; i++)
277 group_open_item_submit (group_open_item_create (
278 new_path.nodes[i]->command_id,
279 new_path.nodes[i]->label));
281 free_path (&old_path);
282 free_path (&new_path);
286 run_convert (int argc UNUSED, char **argv)
288 struct spv_reader *spv;
289 char *err = spv_open (argv[1], &spv);
291 error (1, 0, "%s", err);
294 spv_item_set_table_look (spv_get_root (spv), table_look);
296 output_engine_push ();
297 output_set_filename (argv[1]);
298 string_map_replace (&output_options, "output-file", argv[2]);
299 struct output_driver *driver = output_driver_create (&output_options);
302 output_driver_register (driver);
304 const struct page_setup *ps = spv_get_page_setup (spv);
306 page_setup_item_submit (page_setup_item_create (ps));
308 struct spv_item **items;
310 spv_select (spv, criteria, n_criteria, &items, &n_items);
311 struct spv_item *prev_heading = spv_get_root (spv);
312 for (size_t i = 0; i < n_items; i++)
314 struct spv_item *heading
315 = items[i]->type == SPV_ITEM_HEADING ? items[i] : items[i]->parent;
316 dump_heading_transition (prev_heading, heading);
318 if (set_label && spv_item_is_table (items[i]))
320 printf ("set label to %s\n", set_label);
321 free (items[i]->label);
322 items[i]->label = xstrdup (set_label);
325 dump_item (items[i]);
326 prev_heading = heading;
328 dump_heading_transition (prev_heading, spv_get_root (spv));
333 output_engine_pop ();
336 if (n_warnings && !force)
338 /* XXX There could be other files to unlink, e.g. the ascii driver can
339 produce additional files with the charts. */
344 static const struct pivot_table *
345 get_first_table (const struct spv_reader *spv)
347 struct spv_item **items;
349 spv_select (spv, criteria, n_criteria, &items, &n_items);
351 for (size_t i = 0; i < n_items; i++)
352 if (spv_item_is_table (items[i]))
355 return spv_item_get_table (items[i]);
363 run_get_table_look (int argc UNUSED, char **argv)
365 struct spv_reader *spv;
366 char *err = spv_open (argv[1], &spv);
368 error (1, 0, "%s", err);
370 const struct pivot_table *table = get_first_table (spv);
372 error (1, 0, "%s: no tables found", argv[1]);
374 err = spv_table_look_write (argv[2], pivot_table_get_look (table));
376 error (1, 0, "%s", err);
382 run_convert_table_look (int argc UNUSED, char **argv)
384 struct pivot_table_look *look;
385 char *err = spv_table_look_read (argv[1], &look);
387 error (1, 0, "%s", err);
389 err = spv_table_look_write (argv[2], look);
391 error (1, 0, "%s", err);
393 pivot_table_look_unref (look);
398 run_dump (int argc UNUSED, char **argv)
400 struct spv_reader *spv;
401 char *err = spv_open (argv[1], &spv);
403 error (1, 0, "%s", err);
405 struct spv_item **items;
407 spv_select (spv, criteria, n_criteria, &items, &n_items);
408 for (size_t i = 0; i < n_items; i++)
409 if (items[i]->type == SPV_ITEM_TABLE)
411 pivot_table_dump (spv_item_get_table (items[i]), 0);
420 compare_borders (const void *a_, const void *b_)
422 const struct spvlb_border *const *ap = a_;
423 const struct spvlb_border *const *bp = b_;
424 uint32_t a = (*ap)->border_type;
425 uint32_t b = (*bp)->border_type;
427 return a < b ? -1 : a > b;
431 compare_cells (const void *a_, const void *b_)
433 const struct spvlb_cell *const *ap = a_;
434 const struct spvlb_cell *const *bp = b_;
435 uint64_t a = (*ap)->index;
436 uint64_t b = (*bp)->index;
438 return a < b ? -1 : a > b;
442 run_dump_light_table (int argc UNUSED, char **argv)
444 if (raw && isatty (STDOUT_FILENO))
445 error (1, 0, "not writing binary data to tty");
447 struct spv_reader *spv;
448 char *err = spv_open (argv[1], &spv);
450 error (1, 0, "%s", err);
452 struct spv_item **items;
454 spv_select (spv, criteria, n_criteria, &items, &n_items);
455 for (size_t i = 0; i < n_items; i++)
457 if (!spv_item_is_light_table (items[i]))
465 error = spv_item_get_raw_light_table (items[i], &data, &size);
468 fwrite (data, size, 1, stdout);
474 struct spvlb_table *table;
475 error = spv_item_get_light_table (items[i], &table);
480 qsort (table->borders->borders, table->borders->n_borders,
481 sizeof *table->borders->borders, compare_borders);
482 qsort (table->cells->cells, table->cells->n_cells,
483 sizeof *table->cells->cells, compare_cells);
485 spvlb_print_table (items[i]->bin_member, 0, table);
486 spvlb_free_table (table);
491 msg (ME, "%s", error);
502 run_dump_legacy_data (int argc UNUSED, char **argv)
504 struct spv_reader *spv;
505 char *err = spv_open (argv[1], &spv);
507 error (1, 0, "%s", err);
509 struct spv_item **items;
511 spv_select (spv, criteria, n_criteria, &items, &n_items);
512 for (size_t i = 0; i < n_items; i++)
513 if (spv_item_is_legacy_table (items[i]))
515 struct spv_data data;
521 error = spv_item_get_raw_legacy_data (items[i], &data, &size);
524 fwrite (data, size, 1, stdout);
530 error = spv_item_get_legacy_data (items[i], &data);
533 printf ("%s:\n", items[i]->bin_member);
534 spv_data_dump (&data, stdout);
535 spv_data_uninit (&data);
542 msg (ME, "%s", error);
551 /* This is really bogus.
553 XPath doesn't have any notion of a default XML namespace, but all of the
554 elements in the documents we're interested in have a namespace. Thus, we'd
555 need to require the XPath expressions to have a namespace on every single
556 element: vis:sourceVariable, vis:graph, and so on. That's a pain. So,
557 instead, we remove the default namespace from everyplace it occurs. XPath
558 does support the null namespace, so this allows sourceVariable, graph,
561 See http://plasmasturm.org/log/259/ and
562 https://mail.gnome.org/archives/xml/2003-April/msg00144.html for more
565 remove_default_xml_namespace (xmlNode *node)
567 if (node->ns && !node->ns->prefix)
570 for (xmlNode *child = node->children; child; child = child->next)
571 remove_default_xml_namespace (child);
575 register_ns (xmlXPathContext *ctx, const char *prefix, const char *uri)
577 xmlXPathRegisterNs (ctx, CHAR_CAST (xmlChar *, prefix),
578 CHAR_CAST (xmlChar *, uri));
581 static xmlXPathContext *
582 create_xpath_context (xmlDoc *doc)
584 xmlXPathContext *ctx = xmlXPathNewContext (doc);
585 register_ns (ctx, "vgr", "http://xml.spss.com/spss/viewer/viewer-graph");
586 register_ns (ctx, "vizml", "http://xml.spss.com/visualization");
587 register_ns (ctx, "vmd", "http://xml.spss.com/spss/viewer/viewer-model");
588 register_ns (ctx, "vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
589 register_ns (ctx, "vst", "http://xml.spss.com/spss/viewer/viewer-style");
590 register_ns (ctx, "vtb", "http://xml.spss.com/spss/viewer/viewer-table");
591 register_ns (ctx, "vtl", "http://xml.spss.com/spss/viewer/table-looks");
592 register_ns (ctx, "vtt", "http://xml.spss.com/spss/viewer/viewer-treemodel");
593 register_ns (ctx, "vtx", "http://xml.spss.com/spss/viewer/viewer-text");
594 register_ns (ctx, "xsi", "http://www.w3.org/2001/XMLSchema-instance");
599 dump_xml (int argc, char **argv, const char *member_name,
600 char *error_s, xmlDoc *doc)
606 printf ("<!-- %s -->\n", member_name);
607 xmlElemDump (stdout, NULL, xmlDocGetRootElement (doc));
612 bool any_results = false;
614 remove_default_xml_namespace (xmlDocGetRootElement (doc));
615 for (int i = 2; i < argc; i++)
617 xmlXPathContext *xpath_ctx = create_xpath_context (doc);
618 xmlXPathSetContextNode (xmlDocGetRootElement (doc),
620 xmlXPathObject *xpath_obj = xmlXPathEvalExpression(
621 CHAR_CAST (xmlChar *, argv[i]), xpath_ctx);
623 error (1, 0, _("%s: invalid XPath expression"), argv[i]);
625 const xmlNodeSet *nodes = xpath_obj->nodesetval;
626 if (nodes && nodes->nodeNr > 0)
630 printf ("<!-- %s -->\n", member_name);
633 for (size_t j = 0; j < nodes->nodeNr; j++)
635 xmlElemDump (stdout, doc, nodes->nodeTab[j]);
640 xmlXPathFreeObject (xpath_obj);
641 xmlXPathFreeContext (xpath_ctx);
650 printf ("<!-- %s -->\n", member_name);
651 msg (ME, "%s", error_s);
657 run_dump_legacy_table (int argc, char **argv)
659 struct spv_reader *spv;
660 char *err = spv_open (argv[1], &spv);
662 error (1, 0, "%s", err);
664 struct spv_item **items;
666 spv_select (spv, criteria, n_criteria, &items, &n_items);
667 for (size_t i = 0; i < n_items; i++)
668 if (spv_item_is_legacy_table (items[i]))
671 char *error_s = spv_item_get_legacy_table (items[i], &doc);
672 dump_xml (argc, argv, items[i]->xml_member, error_s, doc);
680 run_dump_structure (int argc, char **argv)
682 struct spv_reader *spv;
683 char *err = spv_open (argv[1], &spv);
685 error (1, 0, "%s", err);
687 struct spv_item **items;
689 spv_select (spv, criteria, n_criteria, &items, &n_items);
690 const char *last_structure_member = NULL;
691 for (size_t i = 0; i < n_items; i++)
692 if (!last_structure_member || strcmp (items[i]->structure_member,
693 last_structure_member))
695 last_structure_member = items[i]->structure_member;
698 char *error_s = spv_item_get_structure (items[i], &doc);
699 dump_xml (argc, argv, items[i]->structure_member, error_s, doc);
707 run_is_legacy (int argc UNUSED, char **argv)
709 struct spv_reader *spv;
710 char *err = spv_open (argv[1], &spv);
712 error (1, 0, "%s", err);
714 bool is_legacy = false;
716 struct spv_item **items;
718 spv_select (spv, criteria, n_criteria, &items, &n_items);
719 for (size_t i = 0; i < n_items; i++)
720 if (spv_item_is_legacy_table (items[i]))
729 exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE);
735 int min_args, max_args;
736 void (*run) (int argc, char **argv);
739 static const struct command commands[] =
741 { "detect", 1, 1, run_detect },
742 { "dir", 1, 1, run_directory },
743 { "convert", 2, 2, run_convert },
744 { "get-table-look", 2, 2, run_get_table_look },
745 { "convert-table-look", 2, 2, run_convert_table_look },
747 /* Undocumented commands. */
748 { "dump", 1, 1, run_dump },
749 { "dump-light-table", 1, 1, run_dump_light_table },
750 { "dump-legacy-data", 1, 1, run_dump_legacy_data },
751 { "dump-legacy-table", 1, INT_MAX, run_dump_legacy_table },
752 { "dump-structure", 1, INT_MAX, run_dump_structure },
753 { "is-legacy", 1, 1, run_is_legacy },
755 static const int n_commands = sizeof commands / sizeof *commands;
757 static const struct command *
758 find_command (const char *name)
760 for (size_t i = 0; i < n_commands; i++)
762 const struct command *c = &commands[i];
763 if (!strcmp (name, c->name))
770 emit_msg (const struct msg *m, void *aux UNUSED)
772 if (m->severity == MSG_S_ERROR || m->severity == MSG_S_WARNING)
775 char *s = msg_to_string (m);
776 fprintf (stderr, "%s\n", s);
781 main (int argc, char **argv)
783 set_program_name (argv[0]);
784 msg_set_handler (emit_msg, NULL);
788 parse_options (argc, argv);
794 error (1, 0, _("missing command name (use --help for help)"));
796 const struct command *c = find_command (argv[0]);
798 error (1, 0, _("unknown command \"%s\" (use --help for help)"), argv[0]);
800 int n_args = argc - 1;
801 if (n_args < c->min_args || n_args > c->max_args)
803 if (c->min_args == c->max_args)
806 ngettext ("\"%s\" command takes exactly %d argument",
807 "\"%s\" command takes exactly %d arguments",
808 c->min_args), c->name, c->min_args);
810 else if (c->max_args == INT_MAX)
813 ngettext ("\"%s\" command requires at least %d argument",
814 "\"%s\" command requires at least %d arguments",
815 c->min_args), c->name, c->min_args);
820 _("\"%s\" command requires between %d and %d arguments"),
821 c->name, c->min_args, c->max_args);
827 pivot_table_look_unref (table_look);
830 return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS;
833 static struct spv_criteria *
836 if (!n_criteria || new_criteria)
838 new_criteria = false;
839 if (n_criteria >= allocated_criteria)
840 criteria = x2nrealloc (criteria, &allocated_criteria,
842 criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER;
845 return &criteria[n_criteria - 1];
849 parse_select (char *arg)
851 bool invert = arg[0] == '^';
854 unsigned classes = 0;
855 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
857 if (!strcmp (arg, "all"))
858 classes = SPV_ALL_CLASSES;
859 else if (!strcmp (arg, "help"))
861 puts (_("The following object classes are supported:"));
862 for (int class = 0; class < SPV_N_CLASSES; class++)
863 printf ("- %s\n", spv_item_class_to_string (class));
868 int class = spv_item_class_from_string (token);
869 if (class == SPV_N_CLASSES)
870 error (1, 0, _("%s: unknown object class (use --select=help "
872 classes |= 1u << class;
876 struct spv_criteria *c = get_criteria ();
877 c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes;
880 static struct spv_criteria_match *
881 get_criteria_match (const char **arg)
883 struct spv_criteria *c = get_criteria ();
884 if ((*arg)[0] == '^')
894 parse_commands (const char *arg)
896 struct spv_criteria_match *cm = get_criteria_match (&arg);
897 string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (","));
901 parse_subtypes (const char *arg)
903 struct spv_criteria_match *cm = get_criteria_match (&arg);
904 string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (","));
908 parse_labels (const char *arg)
910 struct spv_criteria_match *cm = get_criteria_match (&arg);
911 string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (","));
915 parse_instances (char *arg)
917 struct spv_criteria *c = get_criteria ();
918 size_t allocated_instances = c->n_instances;
920 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
922 if (c->n_instances >= allocated_instances)
923 c->instances = x2nrealloc (c->instances, &allocated_instances,
924 sizeof *c->instances);
926 c->instances[c->n_instances++] = (!strcmp (token, "last") ? -1
932 parse_nth_commands (char *arg)
934 struct spv_criteria *c = get_criteria ();
935 size_t allocated_commands = c->n_commands;
937 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
939 if (c->n_commands >= allocated_commands)
940 c->commands = x2nrealloc (c->commands, &allocated_commands,
941 sizeof *c->commands);
943 c->commands[c->n_commands++] = atoi (token);
948 parse_members (const char *arg)
950 struct spv_criteria *cm = get_criteria ();
951 string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (","));
955 parse_table_look (const char *arg)
957 pivot_table_look_unref (table_look);
959 char *error_s = spv_table_look_read (arg, &table_look);
961 error (1, 0, "%s", error_s);
965 parse_options (int argc, char *argv[])
971 OPT_MEMBER_NAMES = UCHAR_MAX + 1,
987 static const struct option long_options[] =
989 /* Input selection options. */
990 { "show-hidden", no_argument, NULL, OPT_SHOW_HIDDEN },
991 { "select", required_argument, NULL, OPT_SELECT },
992 { "commands", required_argument, NULL, OPT_COMMANDS },
993 { "nth-commands", required_argument, NULL, OPT_NTH_COMMANDS },
994 { "subtypes", required_argument, NULL, OPT_SUBTYPES },
995 { "labels", required_argument, NULL, OPT_LABELS },
996 { "instances", required_argument, NULL, OPT_INSTANCES },
997 { "members", required_argument, NULL, OPT_MEMBERS },
998 { "errors", no_argument, NULL, OPT_ERRORS },
999 { "or", no_argument, NULL, OPT_OR },
1001 /* "dir" command options. */
1002 { "member-names", no_argument, NULL, OPT_MEMBER_NAMES },
1004 /* "convert" command options. */
1005 { "force", no_argument, NULL, 'f' },
1006 { "table-look", required_argument, NULL, OPT_TABLE_LOOK },
1007 { "set-label", required_argument, NULL, OPT_SET_LABEL },
1009 /* "dump-light-table" command options. */
1010 { "sort", no_argument, NULL, OPT_SORT },
1011 { "raw", no_argument, NULL, OPT_RAW },
1013 { "help", no_argument, NULL, 'h' },
1014 { "version", no_argument, NULL, 'v' },
1016 { NULL, 0, NULL, 0 },
1021 c = getopt_long (argc, argv, "O:hvf", long_options, NULL);
1028 output_driver_parse_option (optarg, &output_options);
1031 case OPT_MEMBER_NAMES:
1032 show_member_names = true;
1035 case OPT_SHOW_HIDDEN:
1036 get_criteria ()->include_hidden = true;
1040 parse_select (optarg);
1044 parse_commands (optarg);
1047 case OPT_NTH_COMMANDS:
1048 parse_nth_commands (optarg);
1052 parse_subtypes (optarg);
1056 parse_labels (optarg);
1060 parse_instances (optarg);
1064 parse_members (optarg);
1068 get_criteria ()->error = true;
1072 new_criteria = true;
1083 case OPT_TABLE_LOOK:
1084 parse_table_look (optarg);
1096 version_etc (stdout, "pspp-output", PACKAGE_NAME, PACKAGE_VERSION,
1097 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
1098 exit (EXIT_SUCCESS);
1102 exit (EXIT_SUCCESS);
1105 exit (EXIT_FAILURE);
1113 struct string s = DS_EMPTY_INITIALIZER;
1114 struct string_set formats = STRING_SET_INITIALIZER(formats);
1115 output_get_supported_formats (&formats);
1117 const struct string_set_node *node;
1118 STRING_SET_FOR_EACH (format, node, &formats)
1120 if (!ds_is_empty (&s))
1121 ds_put_byte (&s, ' ');
1122 ds_put_cstr (&s, format);
1124 string_set_destroy (&formats);
1127 %s, a utility for working with SPSS viewer (.spv) files.\n\
1128 Usage: %s [OPTION]... COMMAND ARG...\n\
1130 The following commands are available:\n\
1131 detect FILE Detect whether FILE is an SPV file.\n\
1132 dir FILE List tables and other items in FILE.\n\
1133 convert SOURCE DEST Convert .spv SOURCE to DEST.\n\
1134 get-table-look SOURCE DEST Copies first selected TableLook into DEST\n\
1135 convert-table-look SOURCE DEST Copies .tlo or .stt SOURCE into DEST\n\
1137 Input selection options for \"dir\" and \"convert\":\n\
1138 --select=CLASS... include only some kinds of objects\n\
1139 --select=help print known object classes\n\
1140 --commands=COMMAND... include only specified COMMANDs\n\
1141 --nth-commands=N... include only the Nth instance of selected commands\n\
1142 --subtypes=SUBTYPE... include only specified SUBTYPEs of output\n\
1143 --labels=LABEL... include only output objects with the given LABELs\n\
1144 --instances=INSTANCE... include only the given object INSTANCEs\n\
1145 --show-hidden include hidden output objects\n\
1146 --or separate two sets of selection options\n\
1148 \"convert\" by default infers the destination's format from its extension.\n\
1149 The known extensions are: %s\n\
1150 The following options override \"convert\" behavior:\n\
1151 -O format=FORMAT set destination format to FORMAT\n\
1152 -O OPTION=VALUE set output option\n\
1153 -f, --force keep output file even given errors\n\
1154 --table-look=FILE override tables' style with TableLook from FILE\n\
1156 --help display this help and exit\n\
1157 --version output version information and exit\n",
1158 program_name, program_name, ds_cstr (&s));