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 /* The strings below are not marked for translation because they are only
97 useful to developers. */
99 ? xasprintf ("%s and %s:", x, b)
100 : xasprintf ("%s:", x ? x : b));
101 text_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s,
102 xstrdup ("Member Names")));
105 switch (spv_item_get_type (item))
107 case SPV_ITEM_HEADING:
111 spv_text_submit (item);
115 pivot_table_submit (pivot_table_ref (spv_item_get_table (item)));
124 case SPV_ITEM_OBJECT:
136 print_item_directory (const struct spv_item *item)
138 for (int i = 1; i < spv_item_get_level (item); i++)
141 enum spv_item_type type = spv_item_get_type (item);
142 printf ("- %s", spv_item_type_to_string (type));
144 const char *label = spv_item_get_label (item);
146 printf (" \"%s\"", label);
148 if (type == SPV_ITEM_TABLE)
150 const struct pivot_table *table = spv_item_get_table (item);
151 char *title = pivot_value_to_string (table->title, table);
152 if (!label || strcmp (title, label))
153 printf (" title \"%s\"", title);
157 const char *command_id = spv_item_get_command_id (item);
159 printf (" command \"%s\"", command_id);
161 const char *subtype = spv_item_get_subtype (item);
162 if (subtype && (!label || strcmp (label, subtype)))
163 printf (" subtype \"%s\"", subtype);
165 if (!spv_item_is_visible (item))
166 printf (" (hidden)");
167 if (show_member_names && (item->xml_member || item->bin_member))
169 if (item->xml_member && item->bin_member)
170 printf (" in %s and %s", item->xml_member, item->bin_member);
171 else if (item->xml_member)
172 printf (" in %s", item->xml_member);
173 else if (item->bin_member)
174 printf (" in %s", item->bin_member);
180 run_detect (int argc UNUSED, char **argv)
182 char *err = spv_detect (argv[1]);
184 error (1, 0, "%s", err);
188 run_directory (int argc UNUSED, char **argv)
190 struct spv_reader *spv;
191 char *err = spv_open (argv[1], &spv);
193 error (1, 0, "%s", err);
195 struct spv_item **items;
197 spv_select (spv, criteria, n_criteria, &items, &n_items);
198 for (size_t i = 0; i < n_items; i++)
199 print_item_directory (items[i]);
207 const struct spv_item **nodes;
211 const struct spv_item *stub[N_STUB];
215 swap_nodes (const struct spv_item **a, const struct spv_item **b)
217 const struct spv_item *tmp = *a;
223 get_path (const struct spv_item *item, struct item_path *path)
225 size_t allocated = 10;
226 path->nodes = path->stub;
231 if (path->n >= allocated)
233 if (path->nodes == path->stub)
234 path->nodes = xmemdup (path->stub, sizeof path->stub);
235 path->nodes = x2nrealloc (path->nodes, &allocated,
236 sizeof *path->nodes);
238 path->nodes[path->n++] = item;
242 for (size_t i = 0; i < path->n / 2; i++)
243 swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]);
247 free_path (struct item_path *path)
249 if (path && path->nodes != path->stub)
254 dump_heading_transition (const struct spv_item *old,
255 const struct spv_item *new)
260 struct item_path old_path, new_path;
261 get_path (old, &old_path);
262 get_path (new, &new_path);
265 for (; common < old_path.n && common < new_path.n; common++)
266 if (old_path.nodes[common] != new_path.nodes[common])
269 for (size_t i = common; i < old_path.n; i++)
270 group_close_item_submit (group_close_item_create ());
271 for (size_t i = common; i < new_path.n; i++)
272 group_open_item_submit (group_open_item_create (
273 new_path.nodes[i]->command_id,
274 new_path.nodes[i]->label));
276 free_path (&old_path);
277 free_path (&new_path);
281 run_convert (int argc UNUSED, char **argv)
283 struct spv_reader *spv;
284 char *err = spv_open (argv[1], &spv);
286 error (1, 0, "%s", err);
289 spv_item_set_table_look (spv_get_root (spv), table_look);
291 output_engine_push ();
292 output_set_filename (argv[1]);
293 string_map_replace (&output_options, "output-file", argv[2]);
294 struct output_driver *driver = output_driver_create (&output_options);
297 output_driver_register (driver);
299 const struct page_setup *ps = spv_get_page_setup (spv);
301 page_setup_item_submit (page_setup_item_create (ps));
303 struct spv_item **items;
305 spv_select (spv, criteria, n_criteria, &items, &n_items);
306 struct spv_item *prev_heading = spv_get_root (spv);
307 for (size_t i = 0; i < n_items; i++)
309 struct spv_item *heading
310 = items[i]->type == SPV_ITEM_HEADING ? items[i] : items[i]->parent;
311 dump_heading_transition (prev_heading, heading);
312 dump_item (items[i]);
313 prev_heading = heading;
315 dump_heading_transition (prev_heading, spv_get_root (spv));
320 output_engine_pop ();
323 if (n_warnings && !force)
325 /* XXX There could be other files to unlink, e.g. the ascii driver can
326 produce additional files with the charts. */
331 static const struct pivot_table *
332 get_first_table (const struct spv_reader *spv)
334 struct spv_item **items;
336 spv_select (spv, criteria, n_criteria, &items, &n_items);
338 for (size_t i = 0; i < n_items; i++)
339 if (spv_item_is_table (items[i]))
342 return spv_item_get_table (items[i]);
350 run_get_table_look (int argc UNUSED, char **argv)
352 struct pivot_table_look *look;
353 if (strcmp (argv[1], "-"))
355 struct spv_reader *spv;
356 char *err = spv_open (argv[1], &spv);
358 error (1, 0, "%s", err);
360 const struct pivot_table *table = get_first_table (spv);
362 error (1, 0, "%s: no tables found", argv[1]);
364 look = pivot_table_look_ref (pivot_table_get_look (table));
369 look = pivot_table_look_ref (pivot_table_look_builtin_default ());
371 char *err = spv_table_look_write (argv[2], look);
373 error (1, 0, "%s", err);
375 pivot_table_look_unref (look);
379 run_convert_table_look (int argc UNUSED, char **argv)
381 struct pivot_table_look *look;
382 char *err = spv_table_look_read (argv[1], &look);
384 error (1, 0, "%s", err);
386 err = spv_table_look_write (argv[2], look);
388 error (1, 0, "%s", err);
390 pivot_table_look_unref (look);
395 run_dump (int argc UNUSED, char **argv)
397 struct spv_reader *spv;
398 char *err = spv_open (argv[1], &spv);
400 error (1, 0, "%s", err);
402 struct spv_item **items;
404 spv_select (spv, criteria, n_criteria, &items, &n_items);
405 for (size_t i = 0; i < n_items; i++)
406 if (items[i]->type == SPV_ITEM_TABLE)
408 pivot_table_dump (spv_item_get_table (items[i]), 0);
417 compare_borders (const void *a_, const void *b_)
419 const struct spvlb_border *const *ap = a_;
420 const struct spvlb_border *const *bp = b_;
421 uint32_t a = (*ap)->border_type;
422 uint32_t b = (*bp)->border_type;
424 return a < b ? -1 : a > b;
428 compare_cells (const void *a_, const void *b_)
430 const struct spvlb_cell *const *ap = a_;
431 const struct spvlb_cell *const *bp = b_;
432 uint64_t a = (*ap)->index;
433 uint64_t b = (*bp)->index;
435 return a < b ? -1 : a > b;
439 run_dump_light_table (int argc UNUSED, char **argv)
441 if (raw && isatty (STDOUT_FILENO))
442 error (1, 0, "not writing binary data to tty");
444 struct spv_reader *spv;
445 char *err = spv_open (argv[1], &spv);
447 error (1, 0, "%s", err);
449 struct spv_item **items;
451 spv_select (spv, criteria, n_criteria, &items, &n_items);
452 for (size_t i = 0; i < n_items; i++)
454 if (!spv_item_is_light_table (items[i]))
462 error = spv_item_get_raw_light_table (items[i], &data, &size);
465 fwrite (data, size, 1, stdout);
471 struct spvlb_table *table;
472 error = spv_item_get_light_table (items[i], &table);
477 qsort (table->borders->borders, table->borders->n_borders,
478 sizeof *table->borders->borders, compare_borders);
479 qsort (table->cells->cells, table->cells->n_cells,
480 sizeof *table->cells->cells, compare_cells);
482 spvlb_print_table (items[i]->bin_member, 0, table);
483 spvlb_free_table (table);
488 msg (ME, "%s", error);
499 run_dump_legacy_data (int argc UNUSED, char **argv)
501 struct spv_reader *spv;
502 char *err = spv_open (argv[1], &spv);
504 error (1, 0, "%s", err);
506 struct spv_item **items;
508 spv_select (spv, criteria, n_criteria, &items, &n_items);
509 for (size_t i = 0; i < n_items; i++)
510 if (spv_item_is_legacy_table (items[i]))
512 struct spv_data data;
518 error = spv_item_get_raw_legacy_data (items[i], &data, &size);
521 fwrite (data, size, 1, stdout);
527 error = spv_item_get_legacy_data (items[i], &data);
530 printf ("%s:\n", items[i]->bin_member);
531 spv_data_dump (&data, stdout);
532 spv_data_uninit (&data);
539 msg (ME, "%s", error);
548 /* This is really bogus.
550 XPath doesn't have any notion of a default XML namespace, but all of the
551 elements in the documents we're interested in have a namespace. Thus, we'd
552 need to require the XPath expressions to have a namespace on every single
553 element: vis:sourceVariable, vis:graph, and so on. That's a pain. So,
554 instead, we remove the default namespace from everyplace it occurs. XPath
555 does support the null namespace, so this allows sourceVariable, graph,
558 See http://plasmasturm.org/log/259/ and
559 https://mail.gnome.org/archives/xml/2003-April/msg00144.html for more
562 remove_default_xml_namespace (xmlNode *node)
564 if (node->ns && !node->ns->prefix)
567 for (xmlNode *child = node->children; child; child = child->next)
568 remove_default_xml_namespace (child);
572 register_ns (xmlXPathContext *ctx, const char *prefix, const char *uri)
574 xmlXPathRegisterNs (ctx, CHAR_CAST (xmlChar *, prefix),
575 CHAR_CAST (xmlChar *, uri));
578 static xmlXPathContext *
579 create_xpath_context (xmlDoc *doc)
581 xmlXPathContext *ctx = xmlXPathNewContext (doc);
582 register_ns (ctx, "vgr", "http://xml.spss.com/spss/viewer/viewer-graph");
583 register_ns (ctx, "vizml", "http://xml.spss.com/visualization");
584 register_ns (ctx, "vmd", "http://xml.spss.com/spss/viewer/viewer-model");
585 register_ns (ctx, "vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
586 register_ns (ctx, "vst", "http://xml.spss.com/spss/viewer/viewer-style");
587 register_ns (ctx, "vtb", "http://xml.spss.com/spss/viewer/viewer-table");
588 register_ns (ctx, "vtl", "http://xml.spss.com/spss/viewer/table-looks");
589 register_ns (ctx, "vtt", "http://xml.spss.com/spss/viewer/viewer-treemodel");
590 register_ns (ctx, "vtx", "http://xml.spss.com/spss/viewer/viewer-text");
591 register_ns (ctx, "xsi", "http://www.w3.org/2001/XMLSchema-instance");
596 dump_xml (int argc, char **argv, const char *member_name,
597 char *error_s, xmlDoc *doc)
603 printf ("<!-- %s -->\n", member_name);
604 xmlElemDump (stdout, NULL, xmlDocGetRootElement (doc));
609 bool any_results = false;
611 remove_default_xml_namespace (xmlDocGetRootElement (doc));
612 for (int i = 2; i < argc; i++)
614 xmlXPathContext *xpath_ctx = create_xpath_context (doc);
615 xmlXPathSetContextNode (xmlDocGetRootElement (doc),
617 xmlXPathObject *xpath_obj = xmlXPathEvalExpression(
618 CHAR_CAST (xmlChar *, argv[i]), xpath_ctx);
620 error (1, 0, _("%s: invalid XPath expression"), argv[i]);
622 const xmlNodeSet *nodes = xpath_obj->nodesetval;
623 if (nodes && nodes->nodeNr > 0)
627 printf ("<!-- %s -->\n", member_name);
630 for (size_t j = 0; j < nodes->nodeNr; j++)
632 xmlElemDump (stdout, doc, nodes->nodeTab[j]);
637 xmlXPathFreeObject (xpath_obj);
638 xmlXPathFreeContext (xpath_ctx);
647 printf ("<!-- %s -->\n", member_name);
648 msg (ME, "%s", error_s);
654 run_dump_legacy_table (int argc, char **argv)
656 struct spv_reader *spv;
657 char *err = spv_open (argv[1], &spv);
659 error (1, 0, "%s", err);
661 struct spv_item **items;
663 spv_select (spv, criteria, n_criteria, &items, &n_items);
664 for (size_t i = 0; i < n_items; i++)
665 if (spv_item_is_legacy_table (items[i]))
668 char *error_s = spv_item_get_legacy_table (items[i], &doc);
669 dump_xml (argc, argv, items[i]->xml_member, error_s, doc);
677 run_dump_structure (int argc, char **argv)
679 struct spv_reader *spv;
680 char *err = spv_open (argv[1], &spv);
682 error (1, 0, "%s", err);
684 struct spv_item **items;
686 spv_select (spv, criteria, n_criteria, &items, &n_items);
687 const char *last_structure_member = NULL;
688 for (size_t i = 0; i < n_items; i++)
689 if (!last_structure_member || strcmp (items[i]->structure_member,
690 last_structure_member))
692 last_structure_member = items[i]->structure_member;
695 char *error_s = spv_item_get_structure (items[i], &doc);
696 dump_xml (argc, argv, items[i]->structure_member, error_s, doc);
704 run_is_legacy (int argc UNUSED, char **argv)
706 struct spv_reader *spv;
707 char *err = spv_open (argv[1], &spv);
709 error (1, 0, "%s", err);
711 bool is_legacy = false;
713 struct spv_item **items;
715 spv_select (spv, criteria, n_criteria, &items, &n_items);
716 for (size_t i = 0; i < n_items; i++)
717 if (spv_item_is_legacy_table (items[i]))
726 exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE);
732 int min_args, max_args;
733 void (*run) (int argc, char **argv);
736 static const struct command commands[] =
738 { "detect", 1, 1, run_detect },
739 { "dir", 1, 1, run_directory },
740 { "convert", 2, 2, run_convert },
741 { "get-table-look", 2, 2, run_get_table_look },
742 { "convert-table-look", 2, 2, run_convert_table_look },
744 /* Undocumented commands. */
745 { "dump", 1, 1, run_dump },
746 { "dump-light-table", 1, 1, run_dump_light_table },
747 { "dump-legacy-data", 1, 1, run_dump_legacy_data },
748 { "dump-legacy-table", 1, INT_MAX, run_dump_legacy_table },
749 { "dump-structure", 1, INT_MAX, run_dump_structure },
750 { "is-legacy", 1, 1, run_is_legacy },
752 static const int n_commands = sizeof commands / sizeof *commands;
754 static const struct command *
755 find_command (const char *name)
757 for (size_t i = 0; i < n_commands; i++)
759 const struct command *c = &commands[i];
760 if (!strcmp (name, c->name))
767 emit_msg (const struct msg *m, void *aux UNUSED)
769 if (m->severity == MSG_S_ERROR || m->severity == MSG_S_WARNING)
772 char *s = msg_to_string (m);
773 fprintf (stderr, "%s\n", s);
778 main (int argc, char **argv)
780 set_program_name (argv[0]);
781 msg_set_handler (emit_msg, NULL);
785 parse_options (argc, argv);
791 error (1, 0, _("missing command name (use --help for help)"));
793 const struct command *c = find_command (argv[0]);
795 error (1, 0, _("unknown command \"%s\" (use --help for help)"), argv[0]);
797 int n_args = argc - 1;
798 if (n_args < c->min_args || n_args > c->max_args)
800 if (c->min_args == c->max_args)
803 ngettext ("\"%s\" command takes exactly %d argument",
804 "\"%s\" command takes exactly %d arguments",
805 c->min_args), c->name, c->min_args);
807 else if (c->max_args == INT_MAX)
810 ngettext ("\"%s\" command requires at least %d argument",
811 "\"%s\" command requires at least %d arguments",
812 c->min_args), c->name, c->min_args);
817 _("\"%s\" command requires between %d and %d arguments"),
818 c->name, c->min_args, c->max_args);
824 pivot_table_look_unref (table_look);
827 return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS;
830 static struct spv_criteria *
833 if (!n_criteria || new_criteria)
835 new_criteria = false;
836 if (n_criteria >= allocated_criteria)
837 criteria = x2nrealloc (criteria, &allocated_criteria,
839 criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER;
842 return &criteria[n_criteria - 1];
846 parse_select (char *arg)
848 bool invert = arg[0] == '^';
851 unsigned classes = 0;
852 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
854 if (!strcmp (arg, "all"))
855 classes = SPV_ALL_CLASSES;
856 else if (!strcmp (arg, "help"))
858 puts (_("The following object classes are supported:"));
859 for (int class = 0; class < SPV_N_CLASSES; class++)
860 printf ("- %s\n", spv_item_class_to_string (class));
865 int class = spv_item_class_from_string (token);
866 if (class == SPV_N_CLASSES)
867 error (1, 0, _("%s: unknown object class (use --select=help "
869 classes |= 1u << class;
873 struct spv_criteria *c = get_criteria ();
874 c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes;
877 static struct spv_criteria_match *
878 get_criteria_match (const char **arg)
880 struct spv_criteria *c = get_criteria ();
881 if ((*arg)[0] == '^')
891 parse_commands (const char *arg)
893 struct spv_criteria_match *cm = get_criteria_match (&arg);
894 string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (","));
898 parse_subtypes (const char *arg)
900 struct spv_criteria_match *cm = get_criteria_match (&arg);
901 string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (","));
905 parse_labels (const char *arg)
907 struct spv_criteria_match *cm = get_criteria_match (&arg);
908 string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (","));
912 parse_instances (char *arg)
914 struct spv_criteria *c = get_criteria ();
915 size_t allocated_instances = c->n_instances;
917 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
919 if (c->n_instances >= allocated_instances)
920 c->instances = x2nrealloc (c->instances, &allocated_instances,
921 sizeof *c->instances);
923 c->instances[c->n_instances++] = (!strcmp (token, "last") ? -1
929 parse_nth_commands (char *arg)
931 struct spv_criteria *c = get_criteria ();
932 size_t allocated_commands = c->n_commands;
934 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
936 if (c->n_commands >= allocated_commands)
937 c->commands = x2nrealloc (c->commands, &allocated_commands,
938 sizeof *c->commands);
940 c->commands[c->n_commands++] = atoi (token);
945 parse_members (const char *arg)
947 struct spv_criteria *cm = get_criteria ();
948 string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (","));
952 parse_table_look (const char *arg)
954 pivot_table_look_unref (table_look);
956 char *error_s = spv_table_look_read (arg, &table_look);
958 error (1, 0, "%s", error_s);
962 parse_options (int argc, char *argv[])
968 OPT_MEMBER_NAMES = UCHAR_MAX + 1,
983 static const struct option long_options[] =
985 /* Input selection options. */
986 { "show-hidden", no_argument, NULL, OPT_SHOW_HIDDEN },
987 { "select", required_argument, NULL, OPT_SELECT },
988 { "commands", required_argument, NULL, OPT_COMMANDS },
989 { "nth-commands", required_argument, NULL, OPT_NTH_COMMANDS },
990 { "subtypes", required_argument, NULL, OPT_SUBTYPES },
991 { "labels", required_argument, NULL, OPT_LABELS },
992 { "instances", required_argument, NULL, OPT_INSTANCES },
993 { "members", required_argument, NULL, OPT_MEMBERS },
994 { "errors", no_argument, NULL, OPT_ERRORS },
995 { "or", no_argument, NULL, OPT_OR },
997 /* "dir" command options. */
998 { "member-names", no_argument, NULL, OPT_MEMBER_NAMES },
1000 /* "convert" command options. */
1001 { "force", no_argument, NULL, 'f' },
1002 { "table-look", required_argument, NULL, OPT_TABLE_LOOK },
1004 /* "dump-light-table" command options. */
1005 { "sort", no_argument, NULL, OPT_SORT },
1006 { "raw", no_argument, NULL, OPT_RAW },
1008 { "help", no_argument, NULL, 'h' },
1009 { "version", no_argument, NULL, 'v' },
1011 { NULL, 0, NULL, 0 },
1016 c = getopt_long (argc, argv, "O:hvf", long_options, NULL);
1023 output_driver_parse_option (optarg, &output_options);
1026 case OPT_MEMBER_NAMES:
1027 show_member_names = true;
1030 case OPT_SHOW_HIDDEN:
1031 get_criteria ()->include_hidden = true;
1035 parse_select (optarg);
1039 parse_commands (optarg);
1042 case OPT_NTH_COMMANDS:
1043 parse_nth_commands (optarg);
1047 parse_subtypes (optarg);
1051 parse_labels (optarg);
1055 parse_instances (optarg);
1059 parse_members (optarg);
1063 get_criteria ()->error = true;
1067 new_criteria = true;
1078 case OPT_TABLE_LOOK:
1079 parse_table_look (optarg);
1087 version_etc (stdout, "pspp-output", PACKAGE_NAME, PACKAGE_VERSION,
1088 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
1089 exit (EXIT_SUCCESS);
1093 exit (EXIT_SUCCESS);
1096 exit (EXIT_FAILURE);
1104 struct string s = DS_EMPTY_INITIALIZER;
1105 struct string_set formats = STRING_SET_INITIALIZER(formats);
1106 output_get_supported_formats (&formats);
1108 const struct string_set_node *node;
1109 STRING_SET_FOR_EACH (format, node, &formats)
1111 if (!ds_is_empty (&s))
1112 ds_put_byte (&s, ' ');
1113 ds_put_cstr (&s, format);
1115 string_set_destroy (&formats);
1118 %s, a utility for working with SPSS viewer (.spv) files.\n\
1119 Usage: %s [OPTION]... COMMAND ARG...\n\
1121 The following commands are available:\n\
1122 detect FILE Detect whether FILE is an SPV file.\n\
1123 dir FILE List tables and other items in FILE.\n\
1124 convert SOURCE DEST Convert .spv SOURCE to DEST.\n\
1125 get-table-look SOURCE DEST Copies first selected TableLook into DEST\n\
1126 convert-table-look SOURCE DEST Copies .tlo or .stt SOURCE into DEST\n\
1128 Input selection options for \"dir\" and \"convert\":\n\
1129 --select=CLASS... include only some kinds of objects\n\
1130 --select=help print known object classes\n\
1131 --commands=COMMAND... include only specified COMMANDs\n\
1132 --nth-commands=N... include only the Nth instance of selected commands\n\
1133 --subtypes=SUBTYPE... include only specified SUBTYPEs of output\n\
1134 --labels=LABEL... include only output objects with the given LABELs\n\
1135 --instances=INSTANCE... include only the given object INSTANCEs\n\
1136 --show-hidden include hidden output objects\n\
1137 --or separate two sets of selection options\n\
1139 \"convert\" by default infers the destination's format from its extension.\n\
1140 The known extensions are: %s\n\
1141 The following options override \"convert\" behavior:\n\
1142 -O format=FORMAT set destination format to FORMAT\n\
1143 -O OPTION=VALUE set output option\n\
1144 -f, --force keep output file even given errors\n\
1145 --table-look=FILE override tables' style with TableLook from FILE\n\
1147 --help display this help and exit\n\
1148 --version output version information and exit\n",
1149 program_name, program_name, ds_cstr (&s));