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_unref (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
);
811 pivot_table_look_unref (table_look
);
814 return n_warnings
? EXIT_FAILURE
: EXIT_SUCCESS
;
817 static struct spv_criteria
*
820 if (!n_criteria
|| new_criteria
)
822 new_criteria
= false;
823 if (n_criteria
>= allocated_criteria
)
824 criteria
= x2nrealloc (criteria
, &allocated_criteria
,
826 criteria
[n_criteria
++] = (struct spv_criteria
) SPV_CRITERIA_INITIALIZER
;
829 return &criteria
[n_criteria
- 1];
833 parse_select (char *arg
)
835 bool invert
= arg
[0] == '^';
838 unsigned classes
= 0;
839 for (char *token
= strtok (arg
, ","); token
; token
= strtok (NULL
, ","))
841 if (!strcmp (arg
, "all"))
842 classes
= SPV_ALL_CLASSES
;
843 else if (!strcmp (arg
, "help"))
845 puts (_("The following object classes are supported:"));
846 for (int class = 0; class < SPV_N_CLASSES
; class++)
847 printf ("- %s\n", spv_item_class_to_string (class));
852 int class = spv_item_class_from_string (token
);
853 if (class == SPV_N_CLASSES
)
854 error (1, 0, _("%s: unknown object class (use --select=help "
856 classes
|= 1u << class;
860 struct spv_criteria
*c
= get_criteria ();
861 c
->classes
= invert
? classes
^ SPV_ALL_CLASSES
: classes
;
864 static struct spv_criteria_match
*
865 get_criteria_match (const char **arg
)
867 struct spv_criteria
*c
= get_criteria ();
868 if ((*arg
)[0] == '^')
878 parse_commands (const char *arg
)
880 struct spv_criteria_match
*cm
= get_criteria_match (&arg
);
881 string_array_parse (&cm
->commands
, ss_cstr (arg
), ss_cstr (","));
885 parse_subtypes (const char *arg
)
887 struct spv_criteria_match
*cm
= get_criteria_match (&arg
);
888 string_array_parse (&cm
->subtypes
, ss_cstr (arg
), ss_cstr (","));
892 parse_labels (const char *arg
)
894 struct spv_criteria_match
*cm
= get_criteria_match (&arg
);
895 string_array_parse (&cm
->labels
, ss_cstr (arg
), ss_cstr (","));
899 parse_instances (char *arg
)
901 struct spv_criteria
*c
= get_criteria ();
902 size_t allocated_instances
= c
->n_instances
;
904 for (char *token
= strtok (arg
, ","); token
; token
= strtok (NULL
, ","))
906 if (c
->n_instances
>= allocated_instances
)
907 c
->instances
= x2nrealloc (c
->instances
, &allocated_instances
,
908 sizeof *c
->instances
);
910 c
->instances
[c
->n_instances
++] = (!strcmp (token
, "last") ? -1
916 parse_nth_commands (char *arg
)
918 struct spv_criteria
*c
= get_criteria ();
919 size_t allocated_commands
= c
->n_commands
;
921 for (char *token
= strtok (arg
, ","); token
; token
= strtok (NULL
, ","))
923 if (c
->n_commands
>= allocated_commands
)
924 c
->commands
= x2nrealloc (c
->commands
, &allocated_commands
,
925 sizeof *c
->commands
);
927 c
->commands
[c
->n_commands
++] = atoi (token
);
932 parse_members (const char *arg
)
934 struct spv_criteria
*cm
= get_criteria ();
935 string_array_parse (&cm
->members
, ss_cstr (arg
), ss_cstr (","));
939 parse_table_look (const char *arg
)
941 pivot_table_look_unref (table_look
);
943 char *error_s
= spv_table_look_read (arg
, &table_look
);
945 error (1, 0, "%s", error_s
);
949 parse_options (int argc
, char *argv
[])
955 OPT_MEMBER_NAMES
= UCHAR_MAX
+ 1,
970 static const struct option long_options
[] =
972 /* Input selection options. */
973 { "show-hidden", no_argument
, NULL
, OPT_SHOW_HIDDEN
},
974 { "select", required_argument
, NULL
, OPT_SELECT
},
975 { "commands", required_argument
, NULL
, OPT_COMMANDS
},
976 { "nth-commands", required_argument
, NULL
, OPT_NTH_COMMANDS
},
977 { "subtypes", required_argument
, NULL
, OPT_SUBTYPES
},
978 { "labels", required_argument
, NULL
, OPT_LABELS
},
979 { "instances", required_argument
, NULL
, OPT_INSTANCES
},
980 { "members", required_argument
, NULL
, OPT_MEMBERS
},
981 { "errors", no_argument
, NULL
, OPT_ERRORS
},
982 { "or", no_argument
, NULL
, OPT_OR
},
984 /* "dir" command options. */
985 { "member-names", no_argument
, NULL
, OPT_MEMBER_NAMES
},
987 /* "convert" command options. */
988 { "force", no_argument
, NULL
, 'f' },
989 { "table-look", required_argument
, NULL
, OPT_TABLE_LOOK
},
991 /* "dump-light-table" command options. */
992 { "sort", no_argument
, NULL
, OPT_SORT
},
993 { "raw", no_argument
, NULL
, OPT_RAW
},
995 { "help", no_argument
, NULL
, 'h' },
996 { "version", no_argument
, NULL
, 'v' },
998 { NULL
, 0, NULL
, 0 },
1003 c
= getopt_long (argc
, argv
, "O:hvf", long_options
, NULL
);
1010 output_driver_parse_option (optarg
, &output_options
);
1013 case OPT_MEMBER_NAMES
:
1014 show_member_names
= true;
1017 case OPT_SHOW_HIDDEN
:
1018 get_criteria ()->include_hidden
= true;
1022 parse_select (optarg
);
1026 parse_commands (optarg
);
1029 case OPT_NTH_COMMANDS
:
1030 parse_nth_commands (optarg
);
1034 parse_subtypes (optarg
);
1038 parse_labels (optarg
);
1042 parse_instances (optarg
);
1046 parse_members (optarg
);
1050 get_criteria ()->error
= true;
1054 new_criteria
= true;
1065 case OPT_TABLE_LOOK
:
1066 parse_table_look (optarg
);
1074 version_etc (stdout
, "pspp-output", PACKAGE_NAME
, PACKAGE_VERSION
,
1075 "Ben Pfaff", "John Darrington", NULL_SENTINEL
);
1076 exit (EXIT_SUCCESS
);
1080 exit (EXIT_SUCCESS
);
1083 exit (EXIT_FAILURE
);
1091 struct string s
= DS_EMPTY_INITIALIZER
;
1092 struct string_set formats
= STRING_SET_INITIALIZER(formats
);
1093 output_get_supported_formats (&formats
);
1095 const struct string_set_node
*node
;
1096 STRING_SET_FOR_EACH (format
, node
, &formats
)
1098 if (!ds_is_empty (&s
))
1099 ds_put_byte (&s
, ' ');
1100 ds_put_cstr (&s
, format
);
1102 string_set_destroy (&formats
);
1105 %s, a utility for working with SPSS viewer (.spv) files.\n\
1106 Usage: %s [OPTION]... COMMAND ARG...\n\
1108 The following commands are available:\n\
1109 detect FILE Detect whether FILE is an SPV file.\n\
1110 dir FILE List tables and other items in FILE.\n\
1111 convert SOURCE DEST Convert .spv SOURCE to DEST.\n\
1112 get-table-look SOURCE DEST Copies first selected TableLook into DEST\n\
1113 convert-table-look SOURCE DEST Copies .tlo or .stt SOURCE into DEST\n\
1115 Input selection options for \"dir\" and \"convert\":\n\
1116 --select=CLASS... include only some kinds of objects\n\
1117 --select=help print known object classes\n\
1118 --commands=COMMAND... include only specified COMMANDs\n\
1119 --nth-commands=N... include only the Nth instance of selected commands\n\
1120 --subtypes=SUBTYPE... include only specified SUBTYPEs of output\n\
1121 --labels=LABEL... include only output objects with the given LABELs\n\
1122 --instances=INSTANCE... include only the given object INSTANCEs\n\
1123 --show-hidden include hidden output objects\n\
1124 --or separate two sets of selection options\n\
1126 \"convert\" by default infers the destination's format from its extension.\n\
1127 The known extensions are: %s\n\
1128 The following options override \"convert\" behavior:\n\
1129 -O format=FORMAT set destination format to FORMAT\n\
1130 -O OPTION=VALUE set output option\n\
1131 -f, --force keep output file even given errors\n\
1132 --table-look=FILE override tables' style with TableLook from FILE\n\
1134 --help display this help and exit\n\
1135 --version output version information and exit\n",
1136 program_name
, program_name
, ds_cstr (&s
));