New function: xr_draw_eps_chart
[pspp] / utilities / pspp-output.c
1  /* PSPP - a program for statistical analysis.
2    Copyright (C) 2017, 2018 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include <getopt.h>
20 #include <limits.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23
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"
42
43 #include "gl/c-ctype.h"
44 #include "gl/error.h"
45 #include "gl/progname.h"
46 #include "gl/version-etc.h"
47 #include "gl/xalloc.h"
48
49 #include <libxml/tree.h>
50 #include <libxml/xpath.h>
51 #include <libxml/xpathInternals.h>
52
53 #include "gettext.h"
54 #define _(msgid) gettext (msgid)
55
56 /* -O key=value: Output driver options. */
57 static struct string_map output_options
58     = STRING_MAP_INITIALIZER (output_options);
59
60 /* --member-name: Include .zip member name in "dir" output. */
61 static bool show_member_names;
62
63 /* --show-hidden, --select, --commands, ...: Selection criteria. */
64 static struct spv_criteria *criteria;
65 static size_t n_criteria, allocated_criteria;
66
67 /* --or: Add new element to 'criteria' array. */
68 static bool new_criteria;
69
70 /* --sort: Sort members under dump-light-table, to make comparisons easier. */
71 static bool sort;
72
73 /* --raw: Dump raw binary data in dump-light-table. */
74 static bool raw;
75
76 /* -f, --force: Keep output file even on error. */
77 static bool force;
78
79 /* --table-look: TableLook to replace table style for conversion. */
80 static struct pivot_table_look *table_look;
81
82 /* Number of warnings issued. */
83 static size_t n_warnings;
84
85 static void usage (void);
86 static void parse_options (int argc, char **argv);
87
88 static void
89 dump_item (const struct spv_item *item)
90 {
91   if (show_member_names && (item->xml_member || item->bin_member))
92     {
93       const char *x = item->xml_member;
94       const char *b = item->bin_member;
95       char *s = (x && b
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));
99     }
100
101   switch (spv_item_get_type (item))
102     {
103     case SPV_ITEM_HEADING:
104       break;
105
106     case SPV_ITEM_TEXT:
107       spv_text_submit (item);
108       break;
109
110     case SPV_ITEM_TABLE:
111       pivot_table_submit (pivot_table_ref (spv_item_get_table (item)));
112       break;
113
114     case SPV_ITEM_GRAPH:
115       break;
116
117     case SPV_ITEM_MODEL:
118       break;
119
120     case SPV_ITEM_OBJECT:
121       break;
122
123     case SPV_ITEM_TREE:
124       break;
125
126     default:
127       abort ();
128     }
129 }
130
131 static void
132 print_item_directory (const struct spv_item *item)
133 {
134   for (int i = 1; i < spv_item_get_level (item); i++)
135     printf ("    ");
136
137   enum spv_item_type type = spv_item_get_type (item);
138   printf ("- %s", spv_item_type_to_string (type));
139
140   const char *label = spv_item_get_label (item);
141   if (label)
142     printf (" \"%s\"", label);
143
144   if (type == SPV_ITEM_TABLE)
145     {
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);
152       free (title);
153     }
154
155   const char *command_id = spv_item_get_command_id (item);
156   if (command_id)
157     printf (" command \"%s\"", command_id);
158
159   const char *subtype = spv_item_get_subtype (item);
160   if (subtype && (!label || strcmp (label, subtype)))
161     printf (" subtype \"%s\"", subtype);
162
163   if (!spv_item_is_visible (item))
164     printf (" (hidden)");
165   if (show_member_names && (item->xml_member || item->bin_member))
166     {
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);
173     }
174   putchar ('\n');
175 }
176
177 static void
178 run_detect (int argc UNUSED, char **argv)
179 {
180   char *err = spv_detect (argv[1]);
181   if (err)
182     error (1, 0, "%s", err);
183 }
184
185 static void
186 run_directory (int argc UNUSED, char **argv)
187 {
188   struct spv_reader *spv;
189   char *err = spv_open (argv[1], &spv);
190   if (err)
191     error (1, 0, "%s", err);
192
193   struct spv_item **items;
194   size_t n_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]);
198   free (items);
199
200   spv_close (spv);
201 }
202
203 struct item_path
204   {
205     const struct spv_item **nodes;
206     size_t n;
207
208 #define N_STUB 10
209     const struct spv_item *stub[N_STUB];
210   };
211
212 static void
213 swap_nodes (const struct spv_item **a, const struct spv_item **b)
214 {
215   const struct spv_item *tmp = *a;
216   *a = *b;
217   *b = tmp;
218 }
219
220 static void
221 get_path (const struct spv_item *item, struct item_path *path)
222 {
223   size_t allocated = 10;
224   path->nodes = path->stub;
225   path->n = 0;
226
227   while (item)
228     {
229       if (path->n >= allocated)
230         {
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);
235         }
236       path->nodes[path->n++] = item;
237       item = item->parent;
238     }
239
240   for (size_t i = 0; i < path->n / 2; i++)
241     swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]);
242 }
243
244 static void
245 free_path (struct item_path *path)
246 {
247   if (path && path->nodes != path->stub)
248     free (path->nodes);
249 }
250
251 static void
252 dump_heading_transition (const struct spv_item *old,
253                          const struct spv_item *new)
254 {
255   if (old == new)
256     return;
257
258   struct item_path old_path, new_path;
259   get_path (old, &old_path);
260   get_path (new, &new_path);
261
262   size_t common = 0;
263   for (; common < old_path.n && common < new_path.n; common++)
264     if (old_path.nodes[common] != new_path.nodes[common])
265       break;
266
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));
272
273   free_path (&old_path);
274   free_path (&new_path);
275 }
276
277 static void
278 run_convert (int argc UNUSED, char **argv)
279 {
280   struct spv_reader *spv;
281   char *err = spv_open (argv[1], &spv);
282   if (err)
283     error (1, 0, "%s", err);
284
285   if (table_look)
286     spv_item_set_table_look (spv_get_root (spv), table_look);
287
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);
292   if (!driver)
293     exit (EXIT_FAILURE);
294   output_driver_register (driver);
295
296   const struct page_setup *ps = spv_get_page_setup (spv);
297   if (ps)
298     page_setup_item_submit (page_setup_item_create (ps));
299
300   struct spv_item **items;
301   size_t n_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++)
305     {
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;
311     }
312   dump_heading_transition (prev_heading, spv_get_root (spv));
313   free (items);
314
315   spv_close (spv);
316
317   output_engine_pop ();
318   fh_done ();
319
320   if (n_warnings && !force)
321     {
322       /* XXX There could be other files to unlink, e.g. the ascii driver can
323          produce additional files with the charts. */
324       unlink (argv[2]);
325     }
326 }
327
328 static const struct pivot_table *
329 get_first_table (const struct spv_reader *spv)
330 {
331   struct spv_item **items;
332   size_t n_items;
333   spv_select (spv, criteria, n_criteria, &items, &n_items);
334
335   for (size_t i = 0; i < n_items; i++)
336     if (spv_item_is_table (items[i]))
337       {
338         free (items);
339         return spv_item_get_table (items[i]);
340       }
341
342   free (items);
343   return NULL;
344 }
345
346 static void
347 run_get_table_look (int argc UNUSED, char **argv)
348 {
349   struct spv_reader *spv;
350   char *err = spv_open (argv[1], &spv);
351   if (err)
352     error (1, 0, "%s", err);
353
354   const struct pivot_table *table = get_first_table (spv);
355   if (!table)
356     error (1, 0, "%s: no tables found", argv[1]);
357
358   err = spv_table_look_write (argv[2], pivot_table_get_look (table));
359   if (err)
360     error (1, 0, "%s", err);
361
362   spv_close (spv);
363 }
364
365 static void
366 run_dump (int argc UNUSED, char **argv)
367 {
368   struct spv_reader *spv;
369   char *err = spv_open (argv[1], &spv);
370   if (err)
371     error (1, 0, "%s", err);
372
373   struct spv_item **items;
374   size_t n_items;
375   spv_select (spv, criteria, n_criteria, &items, &n_items);
376   for (size_t i = 0; i < n_items; i++)
377     if (items[i]->type == SPV_ITEM_TABLE)
378       {
379         pivot_table_dump (spv_item_get_table (items[i]), 0);
380         putchar ('\n');
381       }
382   free (items);
383
384   spv_close (spv);
385 }
386
387 static int
388 compare_borders (const void *a_, const void *b_)
389 {
390   const struct spvlb_border *const *ap = a_;
391   const struct spvlb_border *const *bp = b_;
392   uint32_t a = (*ap)->border_type;
393   uint32_t b = (*bp)->border_type;
394
395   return a < b ? -1 : a > b;
396 }
397
398 static int
399 compare_cells (const void *a_, const void *b_)
400 {
401   const struct spvlb_cell *const *ap = a_;
402   const struct spvlb_cell *const *bp = b_;
403   uint64_t a = (*ap)->index;
404   uint64_t b = (*bp)->index;
405
406   return a < b ? -1 : a > b;
407 }
408
409 static void
410 run_dump_light_table (int argc UNUSED, char **argv)
411 {
412   if (raw && isatty (STDOUT_FILENO))
413     error (1, 0, "not writing binary data to tty");
414
415   struct spv_reader *spv;
416   char *err = spv_open (argv[1], &spv);
417   if (err)
418     error (1, 0, "%s", err);
419
420   struct spv_item **items;
421   size_t n_items;
422   spv_select (spv, criteria, n_criteria, &items, &n_items);
423   for (size_t i = 0; i < n_items; i++)
424     {
425       if (!spv_item_is_light_table (items[i]))
426         continue;
427
428       char *error;
429       if (raw)
430         {
431           void *data;
432           size_t size;
433           error = spv_item_get_raw_light_table (items[i], &data, &size);
434           if (!error)
435             {
436               fwrite (data, size, 1, stdout);
437               free (data);
438             }
439         }
440       else
441         {
442           struct spvlb_table *table;
443           error = spv_item_get_light_table (items[i], &table);
444           if (!error)
445             {
446               if (sort)
447                 {
448                   qsort (table->borders->borders, table->borders->n_borders,
449                          sizeof *table->borders->borders, compare_borders);
450                   qsort (table->cells->cells, table->cells->n_cells,
451                          sizeof *table->cells->cells, compare_cells);
452                 }
453               spvlb_print_table (items[i]->bin_member, 0, table);
454               spvlb_free_table (table);
455             }
456         }
457       if (error)
458         {
459           msg (ME, "%s", error);
460           free (error);
461         }
462     }
463
464   free (items);
465
466   spv_close (spv);
467 }
468
469 static void
470 run_dump_legacy_data (int argc UNUSED, char **argv)
471 {
472   struct spv_reader *spv;
473   char *err = spv_open (argv[1], &spv);
474   if (err)
475     error (1, 0, "%s", err);
476
477   struct spv_item **items;
478   size_t n_items;
479   spv_select (spv, criteria, n_criteria, &items, &n_items);
480   for (size_t i = 0; i < n_items; i++)
481     if (spv_item_is_legacy_table (items[i]))
482       {
483         struct spv_data data;
484         char *error;
485         if (raw)
486           {
487             void *data;
488             size_t size;
489             error = spv_item_get_raw_legacy_data (items[i], &data, &size);
490             if (!error)
491               {
492                 fwrite (data, size, 1, stdout);
493                 free (data);
494               }
495           }
496         else
497           {
498             error = spv_item_get_legacy_data (items[i], &data);
499             if (!error)
500               {
501                 printf ("%s:\n", items[i]->bin_member);
502                 spv_data_dump (&data, stdout);
503                 spv_data_uninit (&data);
504                 printf ("\n");
505               }
506           }
507
508         if (error)
509           {
510             msg (ME, "%s", error);
511             free (error);
512           }
513       }
514   free (items);
515
516   spv_close (spv);
517 }
518
519 /* This is really bogus.
520
521    XPath doesn't have any notion of a default XML namespace, but all of the
522    elements in the documents we're interested in have a namespace.  Thus, we'd
523    need to require the XPath expressions to have a namespace on every single
524    element: vis:sourceVariable, vis:graph, and so on.  That's a pain.  So,
525    instead, we remove the default namespace from everyplace it occurs.  XPath
526    does support the null namespace, so this allows sourceVariable, graph,
527    etc. to work.
528
529    See http://plasmasturm.org/log/259/ and
530    https://mail.gnome.org/archives/xml/2003-April/msg00144.html for more
531    information.*/
532 static void
533 remove_default_xml_namespace (xmlNode *node)
534 {
535   if (node->ns && !node->ns->prefix)
536     node->ns = NULL;
537
538   for (xmlNode *child = node->children; child; child = child->next)
539     remove_default_xml_namespace (child);
540 }
541
542 static void
543 register_ns (xmlXPathContext *ctx, const char *prefix, const char *uri)
544 {
545   xmlXPathRegisterNs (ctx, CHAR_CAST (xmlChar *, prefix),
546                       CHAR_CAST (xmlChar *, uri));
547 }
548
549 static xmlXPathContext *
550 create_xpath_context (xmlDoc *doc)
551 {
552   xmlXPathContext *ctx = xmlXPathNewContext (doc);
553   register_ns (ctx, "vgr", "http://xml.spss.com/spss/viewer/viewer-graph");
554   register_ns (ctx, "vizml", "http://xml.spss.com/visualization");
555   register_ns (ctx, "vmd", "http://xml.spss.com/spss/viewer/viewer-model");
556   register_ns (ctx, "vps", "http://xml.spss.com/spss/viewer/viewer-pagesetup");
557   register_ns (ctx, "vst", "http://xml.spss.com/spss/viewer/viewer-style");
558   register_ns (ctx, "vtb", "http://xml.spss.com/spss/viewer/viewer-table");
559   register_ns (ctx, "vtl", "http://xml.spss.com/spss/viewer/table-looks");
560   register_ns (ctx, "vtt", "http://xml.spss.com/spss/viewer/viewer-treemodel");
561   register_ns (ctx, "vtx", "http://xml.spss.com/spss/viewer/viewer-text");
562   register_ns (ctx, "xsi", "http://www.w3.org/2001/XMLSchema-instance");
563   return ctx;
564 }
565
566 static void
567 dump_xml (int argc, char **argv, const char *member_name,
568           char *error_s, xmlDoc *doc)
569 {
570   if (!error_s)
571     {
572       if (argc == 2)
573         {
574           printf ("<!-- %s -->\n", member_name);
575           xmlElemDump (stdout, NULL, xmlDocGetRootElement (doc));
576           putchar ('\n');
577         }
578       else
579         {
580           bool any_results = false;
581
582           remove_default_xml_namespace (xmlDocGetRootElement (doc));
583           for (int i = 2; i < argc; i++)
584             {
585               xmlXPathContext *xpath_ctx = create_xpath_context (doc);
586               xmlXPathSetContextNode (xmlDocGetRootElement (doc),
587                                       xpath_ctx);
588               xmlXPathObject *xpath_obj = xmlXPathEvalExpression(
589                 CHAR_CAST (xmlChar *, argv[i]), xpath_ctx);
590               if (!xpath_obj)
591                 error (1, 0, _("%s: invalid XPath expression"), argv[i]);
592
593               const xmlNodeSet *nodes = xpath_obj->nodesetval;
594               if (nodes && nodes->nodeNr > 0)
595                 {
596                   if (!any_results)
597                     {
598                       printf ("<!-- %s -->\n", member_name);
599                       any_results = true;
600                     }
601                   for (size_t j = 0; j < nodes->nodeNr; j++)
602                     {
603                       xmlElemDump (stdout, doc, nodes->nodeTab[j]);
604                       putchar ('\n');
605                     }
606                 }
607
608               xmlXPathFreeObject (xpath_obj);
609               xmlXPathFreeContext (xpath_ctx);
610             }
611           if (any_results)
612             putchar ('\n');;
613         }
614       xmlFreeDoc (doc);
615     }
616   else
617     {
618       printf ("<!-- %s -->\n", member_name);
619       msg (ME, "%s", error_s);
620       free (error_s);
621     }
622 }
623
624 static void
625 run_dump_legacy_table (int argc, char **argv)
626 {
627   struct spv_reader *spv;
628   char *err = spv_open (argv[1], &spv);
629   if (err)
630     error (1, 0, "%s", err);
631
632   struct spv_item **items;
633   size_t n_items;
634   spv_select (spv, criteria, n_criteria, &items, &n_items);
635   for (size_t i = 0; i < n_items; i++)
636     if (spv_item_is_legacy_table (items[i]))
637       {
638         xmlDoc *doc;
639         char *error_s = spv_item_get_legacy_table (items[i], &doc);
640         dump_xml (argc, argv, items[i]->xml_member, error_s, doc);
641       }
642   free (items);
643
644   spv_close (spv);
645 }
646
647 static void
648 run_dump_structure (int argc, char **argv)
649 {
650   struct spv_reader *spv;
651   char *err = spv_open (argv[1], &spv);
652   if (err)
653     error (1, 0, "%s", err);
654
655   struct spv_item **items;
656   size_t n_items;
657   spv_select (spv, criteria, n_criteria, &items, &n_items);
658   const char *last_structure_member = NULL;
659   for (size_t i = 0; i < n_items; i++)
660     if (!last_structure_member || strcmp (items[i]->structure_member,
661                                           last_structure_member))
662       {
663         last_structure_member = items[i]->structure_member;
664
665         xmlDoc *doc;
666         char *error_s = spv_item_get_structure (items[i], &doc);
667         dump_xml (argc, argv, items[i]->structure_member, error_s, doc);
668       }
669   free (items);
670
671   spv_close (spv);
672 }
673
674 static void
675 run_is_legacy (int argc UNUSED, char **argv)
676 {
677   struct spv_reader *spv;
678   char *err = spv_open (argv[1], &spv);
679   if (err)
680     error (1, 0, "%s", err);
681
682   bool is_legacy = false;
683
684   struct spv_item **items;
685   size_t n_items;
686   spv_select (spv, criteria, n_criteria, &items, &n_items);
687   for (size_t i = 0; i < n_items; i++)
688     if (spv_item_is_legacy_table (items[i]))
689       {
690         is_legacy = true;
691         break;
692       }
693   free (items);
694
695   spv_close (spv);
696
697   exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE);
698 }
699
700 struct command
701   {
702     const char *name;
703     int min_args, max_args;
704     void (*run) (int argc, char **argv);
705   };
706
707 static const struct command commands[] =
708   {
709     { "detect", 1, 1, run_detect },
710     { "dir", 1, 1, run_directory },
711     { "convert", 2, 2, run_convert },
712     { "get-table-look", 2, 2, run_get_table_look },
713
714     /* Undocumented commands. */
715     { "dump", 1, 1, run_dump },
716     { "dump-light-table", 1, 1, run_dump_light_table },
717     { "dump-legacy-data", 1, 1, run_dump_legacy_data },
718     { "dump-legacy-table", 1, INT_MAX, run_dump_legacy_table },
719     { "dump-structure", 1, INT_MAX, run_dump_structure },
720     { "is-legacy", 1, 1, run_is_legacy },
721   };
722 static const int n_commands = sizeof commands / sizeof *commands;
723
724 static const struct command *
725 find_command (const char *name)
726 {
727   for (size_t i = 0; i < n_commands; i++)
728     {
729       const struct command *c = &commands[i];
730       if (!strcmp (name, c->name))
731         return c;
732     }
733   return NULL;
734 }
735
736 static void
737 emit_msg (const struct msg *m, void *aux UNUSED)
738 {
739   if (m->severity == MSG_S_ERROR || m->severity == MSG_S_WARNING)
740     n_warnings++;
741
742   char *s = msg_to_string (m);
743   fprintf (stderr, "%s\n", s);
744   free (s);
745 }
746
747 int
748 main (int argc, char **argv)
749 {
750   set_program_name (argv[0]);
751   msg_set_handler (emit_msg, NULL);
752   settings_init ();
753   i18n_init ();
754
755   parse_options (argc, argv);
756
757   argc -= optind;
758   argv += optind;
759
760   if (argc < 1)
761     error (1, 0, _("missing command name (use --help for help)"));
762
763   const struct command *c = find_command (argv[0]);
764   if (!c)
765     error (1, 0, _("unknown command \"%s\" (use --help for help)"), argv[0]);
766
767   int n_args = argc - 1;
768   if (n_args < c->min_args || n_args > c->max_args)
769     {
770       if (c->min_args == c->max_args)
771         {
772           error (1, 0,
773                  ngettext ("\"%s\" command takes exactly %d argument",
774                            "\"%s\" command takes exactly %d arguments",
775                            c->min_args), c->name, c->min_args);
776         }
777       else if (c->max_args == INT_MAX)
778         {
779           error (1, 0,
780                  ngettext ("\"%s\" command requires at least %d argument",
781                            "\"%s\" command requires at least %d arguments",
782                            c->min_args), c->name, c->min_args);
783         }
784       else
785         {
786           error (1, 0,
787                  _("\"%s\" command requires between %d and %d arguments"),
788                  c->name, c->min_args, c->max_args);
789         }
790     }
791
792   c->run (argc, argv);
793
794   if (table_look)
795     {
796       pivot_table_look_uninit (table_look);
797       free (table_look);
798     }
799   i18n_done ();
800
801   return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS;
802 }
803
804 static struct spv_criteria *
805 get_criteria (void)
806 {
807   if (!n_criteria || new_criteria)
808     {
809       new_criteria = false;
810       if (n_criteria >= allocated_criteria)
811         criteria = x2nrealloc (criteria, &allocated_criteria,
812                                sizeof *criteria);
813       criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER;
814     }
815
816   return &criteria[n_criteria - 1];
817 }
818
819 static void
820 parse_select (char *arg)
821 {
822   bool invert = arg[0] == '^';
823   arg += invert;
824
825   unsigned classes = 0;
826   for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
827     {
828       if (!strcmp (arg, "all"))
829         classes = SPV_ALL_CLASSES;
830       else if (!strcmp (arg, "help"))
831         {
832           puts (_("The following object classes are supported:"));
833           for (int class = 0; class < SPV_N_CLASSES; class++)
834             printf ("- %s\n", spv_item_class_to_string (class));
835           exit (0);
836         }
837       else
838         {
839           int class = spv_item_class_from_string (token);
840           if (class == SPV_N_CLASSES)
841             error (1, 0, _("%s: unknown object class (use --select=help "
842                            "for help"), arg);
843           classes |= 1u << class;
844         }
845     }
846
847   struct spv_criteria *c = get_criteria ();
848   c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes;
849 }
850
851 static struct spv_criteria_match *
852 get_criteria_match (const char **arg)
853 {
854   struct spv_criteria *c = get_criteria ();
855   if ((*arg)[0] == '^')
856     {
857       (*arg)++;
858       return &c->exclude;
859     }
860   else
861     return &c->include;
862 }
863
864 static void
865 parse_commands (const char *arg)
866 {
867   struct spv_criteria_match *cm = get_criteria_match (&arg);
868   string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (","));
869 }
870
871 static void
872 parse_subtypes (const char *arg)
873 {
874   struct spv_criteria_match *cm = get_criteria_match (&arg);
875   string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (","));
876 }
877
878 static void
879 parse_labels (const char *arg)
880 {
881   struct spv_criteria_match *cm = get_criteria_match (&arg);
882   string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (","));
883 }
884
885 static void
886 parse_instances (char *arg)
887 {
888   struct spv_criteria *c = get_criteria ();
889   size_t allocated_instances = c->n_instances;
890
891   for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
892     {
893       if (c->n_instances >= allocated_instances)
894         c->instances = x2nrealloc (c->instances, &allocated_instances,
895                                    sizeof *c->instances);
896
897       c->instances[c->n_instances++] = (!strcmp (token, "last") ? -1
898                                         : atoi (token));
899     }
900 }
901
902 static void
903 parse_nth_commands (char *arg)
904 {
905   struct spv_criteria *c = get_criteria ();
906   size_t allocated_commands = c->n_commands;
907
908   for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
909     {
910       if (c->n_commands >= allocated_commands)
911         c->commands = x2nrealloc (c->commands, &allocated_commands,
912                                    sizeof *c->commands);
913
914       c->commands[c->n_commands++] = atoi (token);
915     }
916 }
917
918 static void
919 parse_members (const char *arg)
920 {
921   struct spv_criteria *cm = get_criteria ();
922   string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (","));
923 }
924
925 static void
926 parse_table_look (const char *arg)
927 {
928   if (table_look)
929     {
930       pivot_table_look_uninit (table_look);
931       free (table_look);
932     }
933
934   char *error_s = spv_table_look_read (arg, &table_look);
935   if (error_s)
936     error (1, 0, "%s", error_s);
937 }
938
939 static void
940 parse_options (int argc, char *argv[])
941 {
942   for (;;)
943     {
944       enum
945         {
946           OPT_MEMBER_NAMES = UCHAR_MAX + 1,
947           OPT_SHOW_HIDDEN,
948           OPT_SELECT,
949           OPT_COMMANDS,
950           OPT_NTH_COMMANDS,
951           OPT_SUBTYPES,
952           OPT_LABELS,
953           OPT_INSTANCES,
954           OPT_MEMBERS,
955           OPT_ERRORS,
956           OPT_OR,
957           OPT_SORT,
958           OPT_RAW,
959           OPT_TABLE_LOOK,
960         };
961       static const struct option long_options[] =
962         {
963           /* Input selection options. */
964           { "show-hidden", no_argument, NULL, OPT_SHOW_HIDDEN },
965           { "select", required_argument, NULL, OPT_SELECT },
966           { "commands", required_argument, NULL, OPT_COMMANDS },
967           { "nth-commands", required_argument, NULL, OPT_NTH_COMMANDS },
968           { "subtypes", required_argument, NULL, OPT_SUBTYPES },
969           { "labels", required_argument, NULL, OPT_LABELS },
970           { "instances", required_argument, NULL, OPT_INSTANCES },
971           { "members", required_argument, NULL, OPT_MEMBERS },
972           { "errors", no_argument, NULL, OPT_ERRORS },
973           { "or", no_argument, NULL, OPT_OR },
974
975           /* "dir" command options. */
976           { "member-names", no_argument, NULL, OPT_MEMBER_NAMES },
977
978           /* "convert" command options. */
979           { "force", no_argument, NULL, 'f' },
980           { "table-look", required_argument, NULL, OPT_TABLE_LOOK },
981
982           /* "dump-light-table" command options. */
983           { "sort", no_argument, NULL, OPT_SORT },
984           { "raw", no_argument, NULL, OPT_RAW },
985
986           { "help", no_argument, NULL, 'h' },
987           { "version", no_argument, NULL, 'v' },
988
989           { NULL, 0, NULL, 0 },
990         };
991
992       int c;
993
994       c = getopt_long (argc, argv, "O:hvf", long_options, NULL);
995       if (c == -1)
996         break;
997
998       switch (c)
999         {
1000         case 'O':
1001           output_driver_parse_option (optarg, &output_options);
1002           break;
1003
1004         case OPT_MEMBER_NAMES:
1005           show_member_names = true;
1006           break;
1007
1008         case OPT_SHOW_HIDDEN:
1009           get_criteria ()->include_hidden = true;
1010           break;
1011
1012         case OPT_SELECT:
1013           parse_select (optarg);
1014           break;
1015
1016         case OPT_COMMANDS:
1017           parse_commands (optarg);
1018           break;
1019
1020         case OPT_NTH_COMMANDS:
1021           parse_nth_commands (optarg);
1022           break;
1023
1024         case OPT_SUBTYPES:
1025           parse_subtypes (optarg);
1026           break;
1027
1028         case OPT_LABELS:
1029           parse_labels (optarg);
1030           break;
1031
1032         case OPT_INSTANCES:
1033           parse_instances (optarg);
1034           break;
1035
1036         case OPT_MEMBERS:
1037           parse_members (optarg);
1038           break;
1039
1040         case OPT_ERRORS:
1041           get_criteria ()->error = true;
1042           break;
1043
1044         case OPT_OR:
1045           new_criteria = true;
1046           break;
1047
1048         case OPT_SORT:
1049           sort = true;
1050           break;
1051
1052         case OPT_RAW:
1053           raw = true;
1054           break;
1055
1056         case OPT_TABLE_LOOK:
1057           parse_table_look (optarg);
1058           break;
1059
1060         case 'f':
1061           force = true;
1062           break;
1063
1064         case 'v':
1065           version_etc (stdout, "pspp-output", PACKAGE_NAME, PACKAGE_VERSION,
1066                        "Ben Pfaff", "John Darrington", NULL_SENTINEL);
1067           exit (EXIT_SUCCESS);
1068
1069         case 'h':
1070           usage ();
1071           exit (EXIT_SUCCESS);
1072
1073         default:
1074           exit (EXIT_FAILURE);
1075         }
1076     }
1077 }
1078
1079 static void
1080 usage (void)
1081 {
1082   struct string s = DS_EMPTY_INITIALIZER;
1083   struct string_set formats = STRING_SET_INITIALIZER(formats);
1084   output_get_supported_formats (&formats);
1085   const char *format;
1086   const struct string_set_node *node;
1087   STRING_SET_FOR_EACH (format, node, &formats)
1088     {
1089       if (!ds_is_empty (&s))
1090         ds_put_byte (&s, ' ');
1091       ds_put_cstr (&s, format);
1092     }
1093   string_set_destroy (&formats);
1094
1095   printf ("\
1096 %s, a utility for working with SPSS viewer (.spv) files.\n\
1097 Usage: %s [OPTION]... COMMAND ARG...\n\
1098 \n\
1099 The following commands are available:\n\
1100   detect FILE            Detect whether FILE is an SPV file.\n\
1101   dir FILE               List tables and other items in FILE.\n\
1102   convert SOURCE DEST    Convert .spv SOURCE to DEST.\n\
1103   get-table-look SOURCE DEST  Copies first selected TableLook into DEST\n\
1104 \n\
1105 Input selection options for \"dir\" and \"convert\":\n\
1106   --select=CLASS...   include only some kinds of objects\n\
1107   --select=help       print known object classes\n\
1108   --commands=COMMAND...  include only specified COMMANDs\n\
1109   --nth-commands=N...  include only the Nth instance of selected commands\n\
1110   --subtypes=SUBTYPE...  include only specified SUBTYPEs of output\n\
1111   --labels=LABEL...   include only output objects with the given LABELs\n\
1112   --instances=INSTANCE...  include only the given object INSTANCEs\n\
1113   --show-hidden       include hidden output objects\n\
1114   --or                separate two sets of selection options\n\
1115 \n\
1116 \"convert\" by default infers the destination's format from its extension.\n\
1117 The known extensions are: %s\n\
1118 The following options override \"convert\" behavior:\n\
1119   -O format=FORMAT          set destination format to FORMAT\n\
1120   -O OPTION=VALUE           set output option\n\
1121   -f, --force               keep output file even given errors\n\
1122   --table-look=FILE         override tables' style with TableLook from FILE\n\
1123 Other options:\n\
1124   --help              display this help and exit\n\
1125   --version           output version information and exit\n",
1126           program_name, program_name, ds_cstr (&s));
1127   ds_destroy (&s);
1128 }