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,
152 SETTINGS_VALUE_SHOW_DEFAULT,
153 SETTINGS_VALUE_SHOW_DEFAULT);
154 if (!label || strcmp (title, label))
155 printf (" title \"%s\"", title);
159 const char *command_id = spv_item_get_command_id (item);
161 printf (" command \"%s\"", command_id);
163 const char *subtype = spv_item_get_subtype (item);
164 if (subtype && (!label || strcmp (label, subtype)))
165 printf (" subtype \"%s\"", subtype);
167 if (!spv_item_is_visible (item))
168 printf (" (hidden)");
169 if (show_member_names && (item->xml_member || item->bin_member))
171 if (item->xml_member && item->bin_member)
172 printf (" in %s and %s", item->xml_member, item->bin_member);
173 else if (item->xml_member)
174 printf (" in %s", item->xml_member);
175 else if (item->bin_member)
176 printf (" in %s", item->bin_member);
182 run_detect (int argc UNUSED, char **argv)
184 char *err = spv_detect (argv[1]);
186 error (1, 0, "%s", err);
190 run_directory (int argc UNUSED, char **argv)
192 struct spv_reader *spv;
193 char *err = spv_open (argv[1], &spv);
195 error (1, 0, "%s", err);
197 struct spv_item **items;
199 spv_select (spv, criteria, n_criteria, &items, &n_items);
200 for (size_t i = 0; i < n_items; i++)
201 print_item_directory (items[i]);
209 const struct spv_item **nodes;
213 const struct spv_item *stub[N_STUB];
217 swap_nodes (const struct spv_item **a, const struct spv_item **b)
219 const struct spv_item *tmp = *a;
225 get_path (const struct spv_item *item, struct item_path *path)
227 size_t allocated = 10;
228 path->nodes = path->stub;
233 if (path->n >= allocated)
235 if (path->nodes == path->stub)
236 path->nodes = xmemdup (path->stub, sizeof path->stub);
237 path->nodes = x2nrealloc (path->nodes, &allocated,
238 sizeof *path->nodes);
240 path->nodes[path->n++] = item;
244 for (size_t i = 0; i < path->n / 2; i++)
245 swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]);
249 free_path (struct item_path *path)
251 if (path && path->nodes != path->stub)
256 dump_heading_transition (const struct spv_item *old,
257 const struct spv_item *new)
262 struct item_path old_path, new_path;
263 get_path (old, &old_path);
264 get_path (new, &new_path);
267 for (; common < old_path.n && common < new_path.n; common++)
268 if (old_path.nodes[common] != new_path.nodes[common])
271 for (size_t i = common; i < old_path.n; i++)
272 group_close_item_submit (group_close_item_create ());
273 for (size_t i = common; i < new_path.n; i++)
274 group_open_item_submit (group_open_item_create (
275 new_path.nodes[i]->command_id,
276 new_path.nodes[i]->label));
278 free_path (&old_path);
279 free_path (&new_path);
283 run_convert (int argc UNUSED, char **argv)
285 struct spv_reader *spv;
286 char *err = spv_open (argv[1], &spv);
288 error (1, 0, "%s", err);
291 spv_item_set_table_look (spv_get_root (spv), table_look);
293 output_engine_push ();
294 output_set_filename (argv[1]);
295 string_map_replace (&output_options, "output-file", argv[2]);
296 struct output_driver *driver = output_driver_create (&output_options);
299 output_driver_register (driver);
301 const struct page_setup *ps = spv_get_page_setup (spv);
303 page_setup_item_submit (page_setup_item_create (ps));
305 struct spv_item **items;
307 spv_select (spv, criteria, n_criteria, &items, &n_items);
308 struct spv_item *prev_heading = spv_get_root (spv);
309 for (size_t i = 0; i < n_items; i++)
311 struct spv_item *heading
312 = items[i]->type == SPV_ITEM_HEADING ? items[i] : items[i]->parent;
313 dump_heading_transition (prev_heading, heading);
314 dump_item (items[i]);
315 prev_heading = heading;
317 dump_heading_transition (prev_heading, spv_get_root (spv));
322 output_engine_pop ();
325 if (n_warnings && !force)
327 /* XXX There could be other files to unlink, e.g. the ascii driver can
328 produce additional files with the charts. */
333 static const struct pivot_table *
334 get_first_table (const struct spv_reader *spv)
336 struct spv_item **items;
338 spv_select (spv, criteria, n_criteria, &items, &n_items);
340 for (size_t i = 0; i < n_items; i++)
341 if (spv_item_is_table (items[i]))
344 return spv_item_get_table (items[i]);
352 run_get_table_look (int argc UNUSED, char **argv)
354 struct spv_reader *spv;
355 char *err = spv_open (argv[1], &spv);
357 error (1, 0, "%s", err);
359 const struct pivot_table *table = get_first_table (spv);
361 error (1, 0, "%s: no tables found", argv[1]);
363 err = spv_table_look_write (argv[2], pivot_table_get_look (table));
365 error (1, 0, "%s", err);
371 run_convert_table_look (int argc UNUSED, char **argv)
373 struct pivot_table_look *look;
374 char *err = spv_table_look_read (argv[1], &look);
376 error (1, 0, "%s", err);
378 err = spv_table_look_write (argv[2], look);
380 error (1, 0, "%s", err);
382 pivot_table_look_unref (look);
387 run_dump (int argc UNUSED, char **argv)
389 struct spv_reader *spv;
390 char *err = spv_open (argv[1], &spv);
392 error (1, 0, "%s", err);
394 struct spv_item **items;
396 spv_select (spv, criteria, n_criteria, &items, &n_items);
397 for (size_t i = 0; i < n_items; i++)
398 if (items[i]->type == SPV_ITEM_TABLE)
400 pivot_table_dump (spv_item_get_table (items[i]), 0);
409 compare_borders (const void *a_, const void *b_)
411 const struct spvlb_border *const *ap = a_;
412 const struct spvlb_border *const *bp = b_;
413 uint32_t a = (*ap)->border_type;
414 uint32_t b = (*bp)->border_type;
416 return a < b ? -1 : a > b;
420 compare_cells (const void *a_, const void *b_)
422 const struct spvlb_cell *const *ap = a_;
423 const struct spvlb_cell *const *bp = b_;
424 uint64_t a = (*ap)->index;
425 uint64_t b = (*bp)->index;
427 return a < b ? -1 : a > b;
431 run_dump_light_table (int argc UNUSED, char **argv)
433 if (raw && isatty (STDOUT_FILENO))
434 error (1, 0, "not writing binary data to tty");
436 struct spv_reader *spv;
437 char *err = spv_open (argv[1], &spv);
439 error (1, 0, "%s", err);
441 struct spv_item **items;
443 spv_select (spv, criteria, n_criteria, &items, &n_items);
444 for (size_t i = 0; i < n_items; i++)
446 if (!spv_item_is_light_table (items[i]))
454 error = spv_item_get_raw_light_table (items[i], &data, &size);
457 fwrite (data, size, 1, stdout);
463 struct spvlb_table *table;
464 error = spv_item_get_light_table (items[i], &table);
469 qsort (table->borders->borders, table->borders->n_borders,
470 sizeof *table->borders->borders, compare_borders);
471 qsort (table->cells->cells, table->cells->n_cells,
472 sizeof *table->cells->cells, compare_cells);
474 spvlb_print_table (items[i]->bin_member, 0, table);
475 spvlb_free_table (table);
480 msg (ME, "%s", error);
491 run_dump_legacy_data (int argc UNUSED, char **argv)
493 struct spv_reader *spv;
494 char *err = spv_open (argv[1], &spv);
496 error (1, 0, "%s", err);
498 struct spv_item **items;
500 spv_select (spv, criteria, n_criteria, &items, &n_items);
501 for (size_t i = 0; i < n_items; i++)
502 if (spv_item_is_legacy_table (items[i]))
504 struct spv_data data;
510 error = spv_item_get_raw_legacy_data (items[i], &data, &size);
513 fwrite (data, size, 1, stdout);
519 error = spv_item_get_legacy_data (items[i], &data);
522 printf ("%s:\n", items[i]->bin_member);
523 spv_data_dump (&data, stdout);
524 spv_data_uninit (&data);
531 msg (ME, "%s", error);
540 /* This is really bogus.
542 XPath doesn't have any notion of a default XML namespace, but all of the
543 elements in the documents we're interested in have a namespace. Thus, we'd
544 need to require the XPath expressions to have a namespace on every single
545 element: vis:sourceVariable, vis:graph, and so on. That's a pain. So,
546 instead, we remove the default namespace from everyplace it occurs. XPath
547 does support the null namespace, so this allows sourceVariable, graph,
550 See http://plasmasturm.org/log/259/ and
551 https://mail.gnome.org/archives/xml/2003-April/msg00144.html for more
554 remove_default_xml_namespace (xmlNode *node)
556 if (node->ns && !node->ns->prefix)
559 for (xmlNode *child = node->children; child; child = child->next)
560 remove_default_xml_namespace (child);
564 register_ns (xmlXPathContext *ctx, const char *prefix, const char *uri)
566 xmlXPathRegisterNs (ctx, CHAR_CAST (xmlChar *, prefix),
567 CHAR_CAST (xmlChar *, uri));
570 static xmlXPathContext *
571 create_xpath_context (xmlDoc *doc)
573 xmlXPathContext *ctx = xmlXPathNewContext (doc);
574 register_ns (ctx, "vgr", "http://xml.spss.com/spss/viewer/viewer-graph");
575 register_ns (ctx, "vizml", "http://xml.spss.com/visualization");
576 register_ns (ctx, "vmd", "http://xml.spss.com/spss/viewer/viewer-model");
577 register_ns (ctx, "vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
578 register_ns (ctx, "vst", "http://xml.spss.com/spss/viewer/viewer-style");
579 register_ns (ctx, "vtb", "http://xml.spss.com/spss/viewer/viewer-table");
580 register_ns (ctx, "vtl", "http://xml.spss.com/spss/viewer/table-looks");
581 register_ns (ctx, "vtt", "http://xml.spss.com/spss/viewer/viewer-treemodel");
582 register_ns (ctx, "vtx", "http://xml.spss.com/spss/viewer/viewer-text");
583 register_ns (ctx, "xsi", "http://www.w3.org/2001/XMLSchema-instance");
588 dump_xml (int argc, char **argv, const char *member_name,
589 char *error_s, xmlDoc *doc)
595 printf ("<!-- %s -->\n", member_name);
596 xmlElemDump (stdout, NULL, xmlDocGetRootElement (doc));
601 bool any_results = false;
603 remove_default_xml_namespace (xmlDocGetRootElement (doc));
604 for (int i = 2; i < argc; i++)
606 xmlXPathContext *xpath_ctx = create_xpath_context (doc);
607 xmlXPathSetContextNode (xmlDocGetRootElement (doc),
609 xmlXPathObject *xpath_obj = xmlXPathEvalExpression(
610 CHAR_CAST (xmlChar *, argv[i]), xpath_ctx);
612 error (1, 0, _("%s: invalid XPath expression"), argv[i]);
614 const xmlNodeSet *nodes = xpath_obj->nodesetval;
615 if (nodes && nodes->nodeNr > 0)
619 printf ("<!-- %s -->\n", member_name);
622 for (size_t j = 0; j < nodes->nodeNr; j++)
624 xmlElemDump (stdout, doc, nodes->nodeTab[j]);
629 xmlXPathFreeObject (xpath_obj);
630 xmlXPathFreeContext (xpath_ctx);
639 printf ("<!-- %s -->\n", member_name);
640 msg (ME, "%s", error_s);
646 run_dump_legacy_table (int argc, char **argv)
648 struct spv_reader *spv;
649 char *err = spv_open (argv[1], &spv);
651 error (1, 0, "%s", err);
653 struct spv_item **items;
655 spv_select (spv, criteria, n_criteria, &items, &n_items);
656 for (size_t i = 0; i < n_items; i++)
657 if (spv_item_is_legacy_table (items[i]))
660 char *error_s = spv_item_get_legacy_table (items[i], &doc);
661 dump_xml (argc, argv, items[i]->xml_member, error_s, doc);
669 run_dump_structure (int argc, char **argv)
671 struct spv_reader *spv;
672 char *err = spv_open (argv[1], &spv);
674 error (1, 0, "%s", err);
676 struct spv_item **items;
678 spv_select (spv, criteria, n_criteria, &items, &n_items);
679 const char *last_structure_member = NULL;
680 for (size_t i = 0; i < n_items; i++)
681 if (!last_structure_member || strcmp (items[i]->structure_member,
682 last_structure_member))
684 last_structure_member = items[i]->structure_member;
687 char *error_s = spv_item_get_structure (items[i], &doc);
688 dump_xml (argc, argv, items[i]->structure_member, error_s, doc);
696 run_is_legacy (int argc UNUSED, char **argv)
698 struct spv_reader *spv;
699 char *err = spv_open (argv[1], &spv);
701 error (1, 0, "%s", err);
703 bool is_legacy = false;
705 struct spv_item **items;
707 spv_select (spv, criteria, n_criteria, &items, &n_items);
708 for (size_t i = 0; i < n_items; i++)
709 if (spv_item_is_legacy_table (items[i]))
718 exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE);
724 int min_args, max_args;
725 void (*run) (int argc, char **argv);
728 static const struct command commands[] =
730 { "detect", 1, 1, run_detect },
731 { "dir", 1, 1, run_directory },
732 { "convert", 2, 2, run_convert },
733 { "get-table-look", 2, 2, run_get_table_look },
734 { "convert-table-look", 2, 2, run_convert_table_look },
736 /* Undocumented commands. */
737 { "dump", 1, 1, run_dump },
738 { "dump-light-table", 1, 1, run_dump_light_table },
739 { "dump-legacy-data", 1, 1, run_dump_legacy_data },
740 { "dump-legacy-table", 1, INT_MAX, run_dump_legacy_table },
741 { "dump-structure", 1, INT_MAX, run_dump_structure },
742 { "is-legacy", 1, 1, run_is_legacy },
744 static const int n_commands = sizeof commands / sizeof *commands;
746 static const struct command *
747 find_command (const char *name)
749 for (size_t i = 0; i < n_commands; i++)
751 const struct command *c = &commands[i];
752 if (!strcmp (name, c->name))
759 emit_msg (const struct msg *m, void *aux UNUSED)
761 if (m->severity == MSG_S_ERROR || m->severity == MSG_S_WARNING)
764 char *s = msg_to_string (m);
765 fprintf (stderr, "%s\n", s);
770 main (int argc, char **argv)
772 set_program_name (argv[0]);
773 msg_set_handler (emit_msg, NULL);
777 parse_options (argc, argv);
783 error (1, 0, _("missing command name (use --help for help)"));
785 const struct command *c = find_command (argv[0]);
787 error (1, 0, _("unknown command \"%s\" (use --help for help)"), argv[0]);
789 int n_args = argc - 1;
790 if (n_args < c->min_args || n_args > c->max_args)
792 if (c->min_args == c->max_args)
795 ngettext ("\"%s\" command takes exactly %d argument",
796 "\"%s\" command takes exactly %d arguments",
797 c->min_args), c->name, c->min_args);
799 else if (c->max_args == INT_MAX)
802 ngettext ("\"%s\" command requires at least %d argument",
803 "\"%s\" command requires at least %d arguments",
804 c->min_args), c->name, c->min_args);
809 _("\"%s\" command requires between %d and %d arguments"),
810 c->name, c->min_args, c->max_args);
816 pivot_table_look_unref (table_look);
819 return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS;
822 static struct spv_criteria *
825 if (!n_criteria || new_criteria)
827 new_criteria = false;
828 if (n_criteria >= allocated_criteria)
829 criteria = x2nrealloc (criteria, &allocated_criteria,
831 criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER;
834 return &criteria[n_criteria - 1];
838 parse_select (char *arg)
840 bool invert = arg[0] == '^';
843 unsigned classes = 0;
844 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
846 if (!strcmp (arg, "all"))
847 classes = SPV_ALL_CLASSES;
848 else if (!strcmp (arg, "help"))
850 puts (_("The following object classes are supported:"));
851 for (int class = 0; class < SPV_N_CLASSES; class++)
852 printf ("- %s\n", spv_item_class_to_string (class));
857 int class = spv_item_class_from_string (token);
858 if (class == SPV_N_CLASSES)
859 error (1, 0, _("%s: unknown object class (use --select=help "
861 classes |= 1u << class;
865 struct spv_criteria *c = get_criteria ();
866 c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes;
869 static struct spv_criteria_match *
870 get_criteria_match (const char **arg)
872 struct spv_criteria *c = get_criteria ();
873 if ((*arg)[0] == '^')
883 parse_commands (const char *arg)
885 struct spv_criteria_match *cm = get_criteria_match (&arg);
886 string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (","));
890 parse_subtypes (const char *arg)
892 struct spv_criteria_match *cm = get_criteria_match (&arg);
893 string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (","));
897 parse_labels (const char *arg)
899 struct spv_criteria_match *cm = get_criteria_match (&arg);
900 string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (","));
904 parse_instances (char *arg)
906 struct spv_criteria *c = get_criteria ();
907 size_t allocated_instances = c->n_instances;
909 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
911 if (c->n_instances >= allocated_instances)
912 c->instances = x2nrealloc (c->instances, &allocated_instances,
913 sizeof *c->instances);
915 c->instances[c->n_instances++] = (!strcmp (token, "last") ? -1
921 parse_nth_commands (char *arg)
923 struct spv_criteria *c = get_criteria ();
924 size_t allocated_commands = c->n_commands;
926 for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
928 if (c->n_commands >= allocated_commands)
929 c->commands = x2nrealloc (c->commands, &allocated_commands,
930 sizeof *c->commands);
932 c->commands[c->n_commands++] = atoi (token);
937 parse_members (const char *arg)
939 struct spv_criteria *cm = get_criteria ();
940 string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (","));
944 parse_table_look (const char *arg)
946 pivot_table_look_unref (table_look);
948 char *error_s = spv_table_look_read (arg, &table_look);
950 error (1, 0, "%s", error_s);
954 parse_options (int argc, char *argv[])
960 OPT_MEMBER_NAMES = UCHAR_MAX + 1,
975 static const struct option long_options[] =
977 /* Input selection options. */
978 { "show-hidden", no_argument, NULL, OPT_SHOW_HIDDEN },
979 { "select", required_argument, NULL, OPT_SELECT },
980 { "commands", required_argument, NULL, OPT_COMMANDS },
981 { "nth-commands", required_argument, NULL, OPT_NTH_COMMANDS },
982 { "subtypes", required_argument, NULL, OPT_SUBTYPES },
983 { "labels", required_argument, NULL, OPT_LABELS },
984 { "instances", required_argument, NULL, OPT_INSTANCES },
985 { "members", required_argument, NULL, OPT_MEMBERS },
986 { "errors", no_argument, NULL, OPT_ERRORS },
987 { "or", no_argument, NULL, OPT_OR },
989 /* "dir" command options. */
990 { "member-names", no_argument, NULL, OPT_MEMBER_NAMES },
992 /* "convert" command options. */
993 { "force", no_argument, NULL, 'f' },
994 { "table-look", required_argument, NULL, OPT_TABLE_LOOK },
996 /* "dump-light-table" command options. */
997 { "sort", no_argument, NULL, OPT_SORT },
998 { "raw", no_argument, NULL, OPT_RAW },
1000 { "help", no_argument, NULL, 'h' },
1001 { "version", no_argument, NULL, 'v' },
1003 { NULL, 0, NULL, 0 },
1008 c = getopt_long (argc, argv, "O:hvf", long_options, NULL);
1015 output_driver_parse_option (optarg, &output_options);
1018 case OPT_MEMBER_NAMES:
1019 show_member_names = true;
1022 case OPT_SHOW_HIDDEN:
1023 get_criteria ()->include_hidden = true;
1027 parse_select (optarg);
1031 parse_commands (optarg);
1034 case OPT_NTH_COMMANDS:
1035 parse_nth_commands (optarg);
1039 parse_subtypes (optarg);
1043 parse_labels (optarg);
1047 parse_instances (optarg);
1051 parse_members (optarg);
1055 get_criteria ()->error = true;
1059 new_criteria = true;
1070 case OPT_TABLE_LOOK:
1071 parse_table_look (optarg);
1079 version_etc (stdout, "pspp-output", PACKAGE_NAME, PACKAGE_VERSION,
1080 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
1081 exit (EXIT_SUCCESS);
1085 exit (EXIT_SUCCESS);
1088 exit (EXIT_FAILURE);
1096 struct string s = DS_EMPTY_INITIALIZER;
1097 struct string_set formats = STRING_SET_INITIALIZER(formats);
1098 output_get_supported_formats (&formats);
1100 const struct string_set_node *node;
1101 STRING_SET_FOR_EACH (format, node, &formats)
1103 if (!ds_is_empty (&s))
1104 ds_put_byte (&s, ' ');
1105 ds_put_cstr (&s, format);
1107 string_set_destroy (&formats);
1110 %s, a utility for working with SPSS viewer (.spv) files.\n\
1111 Usage: %s [OPTION]... COMMAND ARG...\n\
1113 The following commands are available:\n\
1114 detect FILE Detect whether FILE is an SPV file.\n\
1115 dir FILE List tables and other items in FILE.\n\
1116 convert SOURCE DEST Convert .spv SOURCE to DEST.\n\
1117 get-table-look SOURCE DEST Copies first selected TableLook into DEST\n\
1118 convert-table-look SOURCE DEST Copies .tlo or .stt SOURCE into DEST\n\
1120 Input selection options for \"dir\" and \"convert\":\n\
1121 --select=CLASS... include only some kinds of objects\n\
1122 --select=help print known object classes\n\
1123 --commands=COMMAND... include only specified COMMANDs\n\
1124 --nth-commands=N... include only the Nth instance of selected commands\n\
1125 --subtypes=SUBTYPE... include only specified SUBTYPEs of output\n\
1126 --labels=LABEL... include only output objects with the given LABELs\n\
1127 --instances=INSTANCE... include only the given object INSTANCEs\n\
1128 --show-hidden include hidden output objects\n\
1129 --or separate two sets of selection options\n\
1131 \"convert\" by default infers the destination's format from its extension.\n\
1132 The known extensions are: %s\n\
1133 The following options override \"convert\" behavior:\n\
1134 -O format=FORMAT set destination format to FORMAT\n\
1135 -O OPTION=VALUE set output option\n\
1136 -f, --force keep output file even given errors\n\
1137 --table-look=FILE override tables' style with TableLook from FILE\n\
1139 --help display this help and exit\n\
1140 --version output version information and exit\n",
1141 program_name, program_name, ds_cstr (&s));