~vcs-imports-ii/pspp/master

« back to all changes in this revision

Viewing changes to utilities/pspp-output.c

  • Committer: Ben Pfaff
  • Date: 2021-01-25 04:51:49 UTC
  • Revision ID: git-v1:507ebaea36737618ef8265a60cd3e9005d9f3457
output: Make groups contain their subitems, and get rid of spv_item.

Until now, the output subsystem has had two different ideas for output
items: struct output_item, which is the primary representation, and
struct spv_item, which represents an output item read from an .spv file.
The biggest difference, until now, has been that spv_item contains its
children, whereas output_item bracketed children inside open/close pairs.
This commit unifies them under output_item, making output_item adopt the
container abstraction.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
#include "libpspp/message.h"
31
31
#include "libpspp/string-map.h"
32
32
#include "libpspp/string-set.h"
 
33
#include "libpspp/zip-reader.h"
33
34
#include "output/driver.h"
34
35
#include "output/output-item.h"
35
36
#include "output/pivot-table.h"
 
37
#include "output/page-setup.h"
 
38
#include "output/select.h"
36
39
#include "output/spv/light-binary-parser.h"
37
40
#include "output/spv/spv-legacy-data.h"
38
41
#include "output/spv/spv-light-decoder.h"
39
 
#include "output/spv/spv-output.h"
40
 
#include "output/spv/spv-select.h"
41
42
#include "output/spv/spv-table-look.h"
42
43
#include "output/spv/spv.h"
43
44
 
62
63
static bool show_member_names;
63
64
 
64
65
/* --show-hidden, --select, --commands, ...: Selection criteria. */
65
 
static struct spv_criteria *criteria;
 
66
static struct output_criteria *criteria;
66
67
static size_t n_criteria, allocated_criteria;
67
68
 
68
69
/* --or: Add new element to 'criteria' array. */
95
96
static void developer_usage (void);
96
97
static void parse_options (int argc, char **argv);
97
98
 
98
 
static void
99
 
dump_item (const struct spv_item *item)
 
99
static struct output_item *
 
100
annotate_member_names (const struct output_item *in)
100
101
{
101
 
  if (show_member_names && (item->xml_member || item->bin_member))
102
 
    {
103
 
      const char *x = item->xml_member;
104
 
      const char *b = item->bin_member;
105
 
 
106
 
      /* The strings below are not marked for translation because they are only
107
 
         useful to developers. */
108
 
      char *s = (x && b
109
 
                 ? xasprintf ("%s and %s:", x, b)
110
 
                 : xasprintf ("%s:", x ? x : b));
111
 
      output_item_submit (text_item_create_nocopy (TEXT_ITEM_TITLE, s,
112
 
                                                   xstrdup ("Member Names")));
113
 
    }
114
 
 
115
 
  switch (spv_item_get_type (item))
116
 
    {
117
 
    case SPV_ITEM_HEADING:
118
 
      break;
119
 
 
120
 
    case SPV_ITEM_TEXT:
121
 
      spv_text_submit (item);
122
 
      break;
123
 
 
124
 
    case SPV_ITEM_TABLE:
125
 
      pivot_table_submit (pivot_table_ref (spv_item_get_table (item)));
126
 
      break;
127
 
 
128
 
    case SPV_ITEM_GRAPH:
129
 
      break;
130
 
 
131
 
    case SPV_ITEM_MODEL:
132
 
      break;
133
 
 
134
 
    case SPV_ITEM_IMAGE:
135
 
      output_item_submit (image_item_create (cairo_surface_reference (
136
 
                                               spv_item_get_image (item))));
137
 
      break;
138
 
 
139
 
    case SPV_ITEM_TREE:
140
 
      break;
141
 
 
142
 
    default:
143
 
      abort ();
144
 
    }
 
102
  if (in->type == OUTPUT_ITEM_GROUP)
 
103
    {
 
104
      struct output_item *out = group_item_clone_empty (in);
 
105
      for (size_t i = 0; i < in->group.n_children; i++)
 
106
        {
 
107
          const struct output_item *item = in->group.children[i];
 
108
          const char *members[4];
 
109
          size_t n = spv_info_get_members (item->spv_info, members,
 
110
                                           sizeof members / sizeof *members);
 
111
          if (n)
 
112
            {
 
113
              struct string s = DS_EMPTY_INITIALIZER;
 
114
              ds_put_cstr (&s, members[0]);
 
115
              for (size_t i = 1; i < n; i++)
 
116
                ds_put_format (&s, " and %s", members[i]);
 
117
              group_item_add_child (out, text_item_create_nocopy (
 
118
                                      TEXT_ITEM_TITLE, ds_steal_cstr (&s),
 
119
                                      xstrdup ("Member Names")));
 
120
            }
 
121
 
 
122
          group_item_add_child (out, output_item_ref (item));
 
123
        }
 
124
      return out;
 
125
    }
 
126
  else
 
127
    return output_item_ref (in);
145
128
}
146
129
 
147
130
static void
148
 
print_item_directory (const struct spv_item *item)
 
131
print_item_directory (const struct output_item *item, int level)
149
132
{
150
 
  for (int i = 1; i < spv_item_get_level (item); i++)
 
133
  for (int i = 0; i < level; i++)
151
134
    printf ("    ");
152
135
 
153
 
  enum spv_item_type type = spv_item_get_type (item);
154
 
  printf ("- %s", spv_item_type_to_string (type));
 
136
  printf ("- %s", output_item_type_to_string (item->type));
155
137
 
156
 
  const char *label = spv_item_get_label (item);
 
138
  const char *label = output_item_get_label (item);
157
139
  if (label)
158
140
    printf (" \"%s\"", label);
159
141
 
160
 
  if (type == SPV_ITEM_TABLE)
 
142
  if (item->type == OUTPUT_ITEM_TABLE)
161
143
    {
162
 
      const struct pivot_table *table = spv_item_get_table (item);
163
 
      char *title = pivot_value_to_string (table->title, table);
 
144
      char *title = pivot_value_to_string (item->table->title, item->table);
164
145
      if (!label || strcmp (title, label))
165
146
        printf (" title \"%s\"", title);
166
147
      free (title);
167
148
    }
168
149
 
169
 
  const char *command_id = spv_item_get_command_id (item);
170
 
  if (command_id)
171
 
    printf (" command \"%s\"", command_id);
172
 
 
173
 
  const char *subtype = spv_item_get_subtype (item);
174
 
  if (subtype && (!label || strcmp (label, subtype)))
175
 
    printf (" subtype \"%s\"", subtype);
176
 
 
177
 
  if (!spv_item_is_visible (item))
178
 
    printf (" (hidden)");
 
150
  if (item->command_name)
 
151
    printf (" command \"%s\"", item->command_name);
 
152
 
 
153
  char *subtype = output_item_get_subtype (item);
 
154
  if (subtype)
 
155
    {
 
156
      if (!label || strcmp (label, subtype))
 
157
        printf (" subtype \"%s\"", subtype);
 
158
      free (subtype);
 
159
    }
 
160
 
 
161
  if (!item->show)
 
162
    printf (" (%s)", item->type == OUTPUT_ITEM_GROUP ? "collapsed" : "hidden");
179
163
 
180
164
  if (show_member_names)
181
165
    {
182
 
      const char *members[] = {
183
 
        item->xml_member,
184
 
        item->bin_member,
185
 
        item->png_member,
186
 
      };
187
 
      size_t n = 0;
 
166
      const char *members[4];
 
167
      size_t n = spv_info_get_members (item->spv_info, members,
 
168
                                       sizeof members / sizeof *members);
188
169
 
189
 
      for (size_t i = 0; i < sizeof members / sizeof *members; i++)
190
 
        if (members[i])
191
 
          printf (" %s %s", n++ == 0 ? "in" : "and", members[i]);
 
170
      for (size_t i = 0; i < n; i++)
 
171
          printf (" %s %s", i == 0 ? "in" : "and", members[i]);
192
172
    }
193
173
  putchar ('\n');
 
174
 
 
175
  if (item->type == OUTPUT_ITEM_GROUP)
 
176
    for (size_t i = 0; i < item->group.n_children; i++)
 
177
      print_item_directory (item->group.children[i], level + 1);
194
178
}
195
179
 
196
180
static void
201
185
    error (1, 0, "%s", err);
202
186
}
203
187
 
 
188
static struct output_item *
 
189
read_and_filter_spv (const char *name, struct page_setup **psp)
 
190
{
 
191
  struct output_item *root;
 
192
  char *err = spv_read (name, &root, psp);
 
193
  if (err)
 
194
    error (1, 0, "%s", err);
 
195
  return output_select (root, criteria, n_criteria);
 
196
}
 
197
 
204
198
static void
205
199
run_directory (int argc UNUSED, char **argv)
206
200
{
207
 
  struct spv_reader *spv;
208
 
  char *err = spv_open (argv[1], &spv);
209
 
  if (err)
210
 
    error (1, 0, "%s", err);
211
 
 
212
 
  struct spv_item **items;
213
 
  size_t n_items;
214
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
215
 
  for (size_t i = 0; i < n_items; i++)
216
 
    print_item_directory (items[i]);
217
 
  free (items);
218
 
 
219
 
  spv_close (spv);
220
 
}
221
 
 
222
 
struct item_path
223
 
  {
224
 
    const struct spv_item **nodes;
225
 
    size_t n;
226
 
 
227
 
#define N_STUB 10
228
 
    const struct spv_item *stub[N_STUB];
229
 
  };
230
 
 
231
 
static void
232
 
swap_nodes (const struct spv_item **a, const struct spv_item **b)
233
 
{
234
 
  const struct spv_item *tmp = *a;
235
 
  *a = *b;
236
 
  *b = tmp;
237
 
}
238
 
 
239
 
static void
240
 
get_path (const struct spv_item *item, struct item_path *path)
241
 
{
242
 
  size_t allocated = 10;
243
 
  path->nodes = path->stub;
244
 
  path->n = 0;
245
 
 
246
 
  while (item)
247
 
    {
248
 
      if (path->n >= allocated)
249
 
        {
250
 
          if (path->nodes == path->stub)
251
 
            path->nodes = xmemdup (path->stub, sizeof path->stub);
252
 
          path->nodes = x2nrealloc (path->nodes, &allocated,
253
 
                                    sizeof *path->nodes);
254
 
        }
255
 
      path->nodes[path->n++] = item;
256
 
      item = item->parent;
257
 
    }
258
 
 
259
 
  for (size_t i = 0; i < path->n / 2; i++)
260
 
    swap_nodes (&path->nodes[i], &path->nodes[path->n - i - 1]);
261
 
}
262
 
 
263
 
static void
264
 
free_path (struct item_path *path)
265
 
{
266
 
  if (path && path->nodes != path->stub)
267
 
    free (path->nodes);
268
 
}
269
 
 
270
 
static void
271
 
dump_heading_transition (const struct spv_item *old,
272
 
                         const struct spv_item *new)
273
 
{
274
 
  if (old == new)
275
 
    return;
276
 
 
277
 
  struct item_path old_path, new_path;
278
 
  get_path (old, &old_path);
279
 
  get_path (new, &new_path);
280
 
 
281
 
  size_t common = 0;
282
 
  for (; common < old_path.n && common < new_path.n; common++)
283
 
    if (old_path.nodes[common] != new_path.nodes[common])
284
 
      break;
285
 
 
286
 
  for (size_t i = common; i < old_path.n; i++)
287
 
    output_item_submit (group_close_item_create ());
288
 
  for (size_t i = common; i < new_path.n; i++)
289
 
    output_item_submit (group_open_item_create (
290
 
                          new_path.nodes[i]->command_id,
291
 
                          new_path.nodes[i]->label));
292
 
 
293
 
  free_path (&old_path);
294
 
  free_path (&new_path);
 
201
  struct output_item *root = read_and_filter_spv (argv[1], NULL);
 
202
  for (size_t i = 0; i < root->group.n_children; i++)
 
203
    print_item_directory (root->group.children[i], 0);
 
204
  output_item_unref (root);
 
205
}
 
206
 
 
207
static void
 
208
set_table_look_recursively (struct output_item *item,
 
209
                            const struct pivot_table_look *look)
 
210
{
 
211
  if (item->type == OUTPUT_ITEM_TABLE)
 
212
    pivot_table_set_look (item->table, look);
 
213
  else if (item->type == OUTPUT_ITEM_GROUP)
 
214
    for (size_t i = 0; i < item->group.n_children; i++)
 
215
      set_table_look_recursively (item->group.children[i], look);
295
216
}
296
217
 
297
218
static void
298
219
run_convert (int argc UNUSED, char **argv)
299
220
{
300
 
  struct spv_reader *spv;
301
 
  char *err = spv_open (argv[1], &spv);
302
 
  if (err)
303
 
    error (1, 0, "%s", err);
304
 
 
 
221
  struct page_setup *ps;
 
222
  struct output_item *root = read_and_filter_spv (argv[1], &ps);
305
223
  if (table_look)
306
 
    spv_item_set_table_look (spv_get_root (spv), table_look);
 
224
    set_table_look_recursively (root, table_look);
 
225
  if (show_member_names)
 
226
    {
 
227
      struct output_item *new_root = annotate_member_names (root);
 
228
      output_item_unref (root);
 
229
      root = new_root;
 
230
    }
307
231
 
308
232
  output_engine_push ();
309
233
  output_set_filename (argv[1]);
313
237
    exit (EXIT_FAILURE);
314
238
  output_driver_register (driver);
315
239
 
316
 
  const struct page_setup *ps = spv_get_page_setup (spv);
317
240
  if (ps)
318
 
    output_item_submit (page_setup_item_create (ps));
319
 
 
320
 
  struct spv_item **items;
321
 
  size_t n_items;
322
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
323
 
  struct spv_item *prev_heading = spv_get_root (spv);
324
 
  for (size_t i = 0; i < n_items; i++)
325
241
    {
326
 
      struct spv_item *heading
327
 
        = items[i]->type == SPV_ITEM_HEADING ? items[i] : items[i]->parent;
328
 
      dump_heading_transition (prev_heading, heading);
329
 
      dump_item (items[i]);
330
 
      prev_heading = heading;
 
242
      output_item_submit (page_setup_item_create (ps));
 
243
      page_setup_destroy (ps);
331
244
    }
332
 
  dump_heading_transition (prev_heading, spv_get_root (spv));
333
 
  free (items);
334
 
 
335
 
  spv_close (spv);
 
245
  output_item_submit_children (root);
336
246
 
337
247
  output_engine_pop ();
338
248
  fh_done ();
346
256
}
347
257
 
348
258
static const struct pivot_table *
349
 
get_first_table (const struct spv_reader *spv)
 
259
get_first_table (const struct output_item *item)
350
260
{
351
 
  struct spv_item **items;
352
 
  size_t n_items;
353
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
354
 
 
355
 
  for (size_t i = 0; i < n_items; i++)
356
 
    if (spv_item_is_table (items[i]))
 
261
  if (item->type == OUTPUT_ITEM_TABLE)
 
262
    return item->table;
 
263
  else if (item->type == OUTPUT_ITEM_GROUP)
 
264
    for (size_t i = 0; i < item->group.n_children; i++)
357
265
      {
358
 
        free (items);
359
 
        return spv_item_get_table (items[i]);
 
266
        const struct pivot_table *table
 
267
          = get_first_table (item->group.children[i]);
 
268
        if (table)
 
269
          return table;
360
270
      }
361
271
 
362
 
  free (items);
363
272
  return NULL;
364
273
}
365
274
 
369
278
  struct pivot_table_look *look;
370
279
  if (strcmp (argv[1], "-"))
371
280
    {
372
 
      struct spv_reader *spv;
373
 
      char *err = spv_open (argv[1], &spv);
374
 
      if (err)
375
 
        error (1, 0, "%s", err);
376
 
 
377
 
      const struct pivot_table *table = get_first_table (spv);
 
281
      struct output_item *root = read_and_filter_spv (argv[1], NULL);
 
282
      const struct pivot_table *table = get_first_table (root);
378
283
      if (!table)
379
284
        error (1, 0, "%s: no tables found", argv[1]);
380
285
 
381
286
      look = pivot_table_look_ref (pivot_table_get_look (table));
382
287
 
383
 
      spv_close (spv);
 
288
      output_item_unref (root);
384
289
    }
385
290
  else
386
291
    look = pivot_table_look_ref (pivot_table_look_builtin_default ());
411
316
static void
412
317
run_dump (int argc UNUSED, char **argv)
413
318
{
414
 
  struct spv_reader *spv;
415
 
  char *err = spv_open (argv[1], &spv);
416
 
  if (err)
417
 
    error (1, 0, "%s", err);
418
 
 
419
 
  struct spv_item **items;
420
 
  size_t n_items;
421
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
422
 
  for (size_t i = 0; i < n_items; i++)
423
 
    if (items[i]->type == SPV_ITEM_TABLE)
424
 
      {
425
 
        pivot_table_dump (spv_item_get_table (items[i]), 0);
426
 
        putchar ('\n');
427
 
      }
428
 
  free (items);
429
 
 
430
 
  spv_close (spv);
 
319
  struct output_item *root = read_and_filter_spv (argv[1], NULL);
 
320
  output_item_dump (root, 0);
 
321
  output_item_unref (root);
431
322
}
432
323
 
433
324
static int
452
343
  return a < b ? -1 : a > b;
453
344
}
454
345
 
 
346
static char * WARN_UNUSED_RESULT
 
347
dump_raw (struct zip_reader *zr, const char *member_name)
 
348
{
 
349
  void *data;
 
350
  size_t size;
 
351
  char *error = zip_member_read_all (zr, member_name, &data, &size);
 
352
  if (!error)
 
353
    {
 
354
      fwrite (data, size, 1, stdout);
 
355
      free (data);
 
356
    }
 
357
  return error;
 
358
}
 
359
 
 
360
static void
 
361
dump_light_table (const struct output_item *item)
 
362
{
 
363
  char *error;
 
364
  if (raw)
 
365
    error = dump_raw (item->spv_info->zip_reader,
 
366
                      item->spv_info->bin_member);
 
367
  else
 
368
    {
 
369
      struct spvlb_table *table;
 
370
      error = spv_read_light_table (item->spv_info->zip_reader,
 
371
                                    item->spv_info->bin_member, &table);
 
372
      if (!error)
 
373
        {
 
374
          if (sort)
 
375
            {
 
376
              qsort (table->borders->borders, table->borders->n_borders,
 
377
                     sizeof *table->borders->borders, compare_borders);
 
378
              qsort (table->cells->cells, table->cells->n_cells,
 
379
                     sizeof *table->cells->cells, compare_cells);
 
380
            }
 
381
          spvlb_print_table (item->spv_info->bin_member, 0, table);
 
382
          spvlb_free_table (table);
 
383
        }
 
384
    }
 
385
  if (error)
 
386
    {
 
387
      msg (ME, "%s", error);
 
388
      free (error);
 
389
    }
 
390
}
 
391
 
455
392
static void
456
393
run_dump_light_table (int argc UNUSED, char **argv)
457
394
{
458
395
  if (raw && isatty (STDOUT_FILENO))
459
396
    error (1, 0, "not writing binary data to tty");
460
397
 
461
 
  struct spv_reader *spv;
462
 
  char *err = spv_open (argv[1], &spv);
463
 
  if (err)
464
 
    error (1, 0, "%s", err);
465
 
 
466
 
  struct spv_item **items;
467
 
  size_t n_items;
468
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
469
 
  for (size_t i = 0; i < n_items; i++)
470
 
    {
471
 
      if (!spv_item_is_light_table (items[i]))
472
 
        continue;
473
 
 
474
 
      char *error;
475
 
      if (raw)
476
 
        {
477
 
          void *data;
478
 
          size_t size;
479
 
          error = spv_item_get_raw_light_table (items[i], &data, &size);
480
 
          if (!error)
481
 
            {
482
 
              fwrite (data, size, 1, stdout);
483
 
              free (data);
484
 
            }
485
 
        }
486
 
      else
487
 
        {
488
 
          struct spvlb_table *table;
489
 
          error = spv_item_get_light_table (items[i], &table);
490
 
          if (!error)
491
 
            {
492
 
              if (sort)
493
 
                {
494
 
                  qsort (table->borders->borders, table->borders->n_borders,
495
 
                         sizeof *table->borders->borders, compare_borders);
496
 
                  qsort (table->cells->cells, table->cells->n_cells,
497
 
                         sizeof *table->cells->cells, compare_cells);
498
 
                }
499
 
              spvlb_print_table (items[i]->bin_member, 0, table);
500
 
              spvlb_free_table (table);
501
 
            }
502
 
        }
503
 
      if (error)
504
 
        {
505
 
          msg (ME, "%s", error);
506
 
          free (error);
507
 
        }
508
 
    }
509
 
 
510
 
  free (items);
511
 
 
512
 
  spv_close (spv);
 
398
  struct output_item *root = read_and_filter_spv (argv[1], NULL);
 
399
  struct output_iterator iter;
 
400
  OUTPUT_ITEM_FOR_EACH (&iter, root)
 
401
    if (iter.cur->type == OUTPUT_ITEM_TABLE && !iter.cur->spv_info->xml_member)
 
402
      dump_light_table (iter.cur);
 
403
  output_item_unref (root);
 
404
}
 
405
 
 
406
static void
 
407
dump_legacy_data (const struct output_item *item)
 
408
{
 
409
  char *error;
 
410
  if (raw)
 
411
    error = dump_raw (item->spv_info->zip_reader,
 
412
                      item->spv_info->bin_member);
 
413
  else
 
414
    {
 
415
      struct spv_data data;
 
416
      error = spv_read_legacy_data (item->spv_info->zip_reader,
 
417
                                    item->spv_info->bin_member, &data);
 
418
      if (!error)
 
419
        {
 
420
          printf ("%s:\n", item->spv_info->bin_member);
 
421
          spv_data_dump (&data, stdout);
 
422
          spv_data_uninit (&data);
 
423
          printf ("\n");
 
424
        }
 
425
    }
 
426
 
 
427
  if (error)
 
428
    {
 
429
      msg (ME, "%s", error);
 
430
      free (error);
 
431
    }
513
432
}
514
433
 
515
434
static void
516
435
run_dump_legacy_data (int argc UNUSED, char **argv)
517
436
{
518
 
  struct spv_reader *spv;
519
 
  char *err = spv_open (argv[1], &spv);
520
 
  if (err)
521
 
    error (1, 0, "%s", err);
522
 
 
523
437
  if (raw && isatty (STDOUT_FILENO))
524
438
    error (1, 0, "not writing binary data to tty");
525
439
 
526
 
  struct spv_item **items;
527
 
  size_t n_items;
528
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
529
 
  for (size_t i = 0; i < n_items; i++)
530
 
    if (spv_item_is_legacy_table (items[i]))
531
 
      {
532
 
        struct spv_data data;
533
 
        char *error;
534
 
        if (raw)
535
 
          {
536
 
            void *data;
537
 
            size_t size;
538
 
            error = spv_item_get_raw_legacy_data (items[i], &data, &size);
539
 
            if (!error)
540
 
              {
541
 
                fwrite (data, size, 1, stdout);
542
 
                free (data);
543
 
              }
544
 
          }
545
 
        else
546
 
          {
547
 
            error = spv_item_get_legacy_data (items[i], &data);
548
 
            if (!error)
549
 
              {
550
 
                printf ("%s:\n", items[i]->bin_member);
551
 
                spv_data_dump (&data, stdout);
552
 
                spv_data_uninit (&data);
553
 
                printf ("\n");
554
 
              }
555
 
          }
556
 
 
557
 
        if (error)
558
 
          {
559
 
            msg (ME, "%s", error);
560
 
            free (error);
561
 
          }
562
 
      }
563
 
  free (items);
564
 
 
565
 
  spv_close (spv);
 
440
  struct output_item *root = read_and_filter_spv (argv[1], NULL);
 
441
  struct output_iterator iter;
 
442
  OUTPUT_ITEM_FOR_EACH (&iter, root)
 
443
    if (iter.cur->type == OUTPUT_ITEM_TABLE
 
444
        && iter.cur->spv_info->xml_member
 
445
        && iter.cur->spv_info->bin_member)
 
446
      dump_legacy_data (iter.cur);
 
447
  output_item_unref (root);
566
448
}
567
449
 
568
450
/* This is really bogus.
671
553
}
672
554
 
673
555
static void
 
556
dump_legacy_table (int argc, char **argv, const struct output_item *item)
 
557
{
 
558
  xmlDoc *doc;
 
559
  char *error_s = spv_read_xml_member (item->spv_info->zip_reader,
 
560
                                       item->spv_info->xml_member,
 
561
                                       false, "visualization", &doc);
 
562
  dump_xml (argc, argv, item->spv_info->xml_member, error_s, doc);
 
563
}
 
564
 
 
565
static void
674
566
run_dump_legacy_table (int argc, char **argv)
675
567
{
676
 
  struct spv_reader *spv;
677
 
  char *err = spv_open (argv[1], &spv);
678
 
  if (err)
679
 
    error (1, 0, "%s", err);
680
 
 
681
 
  struct spv_item **items;
682
 
  size_t n_items;
683
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
684
 
  for (size_t i = 0; i < n_items; i++)
685
 
    if (spv_item_is_legacy_table (items[i]))
686
 
      {
687
 
        xmlDoc *doc;
688
 
        char *error_s = spv_item_get_legacy_table (items[i], &doc);
689
 
        dump_xml (argc, argv, items[i]->xml_member, error_s, doc);
690
 
      }
691
 
  free (items);
692
 
 
693
 
  spv_close (spv);
 
568
  struct output_item *root = read_and_filter_spv (argv[1], NULL);
 
569
  struct output_iterator iter;
 
570
  OUTPUT_ITEM_FOR_EACH (&iter, root)
 
571
    if (iter.cur->type == OUTPUT_ITEM_TABLE
 
572
        && iter.cur->spv_info->xml_member)
 
573
      dump_legacy_table (argc, argv, iter.cur);
 
574
  output_item_unref (root);
 
575
}
 
576
 
 
577
static void
 
578
dump_structure (int argc, char **argv, const struct output_item *item)
 
579
{
 
580
  xmlDoc *doc;
 
581
  char *error_s = spv_read_xml_member (item->spv_info->zip_reader,
 
582
                                       item->spv_info->structure_member,
 
583
                                       true, "heading", &doc);
 
584
  dump_xml (argc, argv, item->spv_info->structure_member, error_s, doc);
694
585
}
695
586
 
696
587
static void
697
588
run_dump_structure (int argc, char **argv)
698
589
{
699
 
  struct spv_reader *spv;
700
 
  char *err = spv_open (argv[1], &spv);
701
 
  if (err)
702
 
    error (1, 0, "%s", err);
 
590
  struct output_item *root = read_and_filter_spv (argv[1], NULL);
703
591
 
704
 
  struct spv_item **items;
705
 
  size_t n_items;
706
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
707
592
  const char *last_structure_member = NULL;
708
 
  for (size_t i = 0; i < n_items; i++)
709
 
    if (!last_structure_member || strcmp (items[i]->structure_member,
710
 
                                          last_structure_member))
711
 
      {
712
 
        last_structure_member = items[i]->structure_member;
713
 
 
714
 
        xmlDoc *doc;
715
 
        char *error_s = spv_item_get_structure (items[i], &doc);
716
 
        dump_xml (argc, argv, items[i]->structure_member, error_s, doc);
717
 
      }
718
 
  free (items);
719
 
 
720
 
  spv_close (spv);
 
593
  struct output_iterator iter;
 
594
  OUTPUT_ITEM_FOR_EACH (&iter, root)
 
595
    {
 
596
      const struct output_item *item = iter.cur;
 
597
      if (item->spv_info->structure_member
 
598
          && (!last_structure_member
 
599
              || strcmp (item->spv_info->structure_member,
 
600
                         last_structure_member)))
 
601
        {
 
602
          last_structure_member = item->spv_info->structure_member;
 
603
          dump_structure (argc, argv, item);
 
604
        }
 
605
    }
 
606
  output_item_unref (root);
 
607
}
 
608
 
 
609
static bool
 
610
is_any_legacy (const struct output_item *item)
 
611
{
 
612
  if (item->type == OUTPUT_ITEM_TABLE)
 
613
    return item->spv_info->xml_member != NULL;
 
614
  else if (item->type == OUTPUT_ITEM_GROUP)
 
615
    for (size_t i = 0; i < item->group.n_children; i++)
 
616
      if (is_any_legacy (item->group.children[i]))
 
617
        return true;
 
618
 
 
619
  return false;
721
620
}
722
621
 
723
622
static void
724
623
run_is_legacy (int argc UNUSED, char **argv)
725
624
{
726
 
  struct spv_reader *spv;
727
 
  char *err = spv_open (argv[1], &spv);
728
 
  if (err)
729
 
    error (1, 0, "%s", err);
730
 
 
731
 
  bool is_legacy = false;
732
 
 
733
 
  struct spv_item **items;
734
 
  size_t n_items;
735
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
736
 
  for (size_t i = 0; i < n_items; i++)
737
 
    if (spv_item_is_legacy_table (items[i]))
738
 
      {
739
 
        is_legacy = true;
740
 
        break;
741
 
      }
742
 
  free (items);
743
 
 
744
 
  spv_close (spv);
 
625
  struct output_item *root = read_and_filter_spv (argv[1], NULL);
 
626
  bool is_legacy = is_any_legacy (root);
 
627
  output_item_unref (root);
745
628
 
746
629
  exit (is_legacy ? EXIT_SUCCESS : EXIT_FAILURE);
747
630
}
801
684
    }
802
685
}
803
686
 
 
687
struct encoded_strings
 
688
  {
 
689
    char *encoding;
 
690
    struct string_array strings;
 
691
  };
 
692
 
 
693
struct encoded_strings_table
 
694
  {
 
695
    struct encoded_strings *es;
 
696
    size_t n, allocated;
 
697
  };
 
698
 
 
699
static void
 
700
collect_strings (const struct output_item *item,
 
701
                 struct encoded_strings_table *t)
 
702
{
 
703
  char *error;
 
704
  struct spvlb_table *table;
 
705
  error = spv_read_light_table (item->spv_info->zip_reader,
 
706
                                item->spv_info->bin_member, &table);
 
707
  if (error)
 
708
    {
 
709
      msg (ME, "%s", error);
 
710
      free (error);
 
711
      return;
 
712
    }
 
713
 
 
714
  const char *table_encoding = spvlb_table_get_encoding (table);
 
715
  size_t j = 0;
 
716
  for (j = 0; j < t->n; j++)
 
717
    if (!strcmp (t->es[j].encoding, table_encoding))
 
718
      break;
 
719
  if (j >= t->n)
 
720
    {
 
721
      if (t->n >= t->allocated)
 
722
        t->es = x2nrealloc (t->es, &t->allocated, sizeof *t->es);
 
723
      t->es[t->n++] = (struct encoded_strings) {
 
724
        .encoding = xstrdup (table_encoding),
 
725
        .strings = STRING_ARRAY_INITIALIZER,
 
726
      };
 
727
    }
 
728
  collect_spvlb_strings (table, &t->es[j].strings);
 
729
}
 
730
 
804
731
static void
805
732
run_strings (int argc UNUSED, char **argv)
806
733
{
807
 
  struct spv_reader *spv;
808
 
  char *err = spv_open (argv[1], &spv);
809
 
  if (err)
810
 
    error (1, 0, "%s", err);
811
 
 
812
 
  struct encoded_strings
813
 
    {
814
 
      char *encoding;
815
 
      struct string_array strings;
816
 
    }
817
 
  *es = NULL;
818
 
  size_t n_es = 0;
819
 
  size_t allocated_es = 0;
820
 
 
821
 
  struct spv_item **items;
822
 
  size_t n_items;
823
 
  spv_select (spv, criteria, n_criteria, &items, &n_items);
824
 
  for (size_t i = 0; i < n_items; i++)
825
 
    {
826
 
      if (!spv_item_is_light_table (items[i]))
827
 
        continue;
828
 
 
829
 
      char *error;
830
 
      struct spvlb_table *table;
831
 
      error = spv_item_get_light_table (items[i], &table);
832
 
      if (error)
833
 
        {
834
 
          msg (ME, "%s", error);
835
 
          free (error);
836
 
          continue;
837
 
        }
838
 
 
839
 
      const char *table_encoding = spvlb_table_get_encoding (table);
840
 
      size_t j = 0;
841
 
      for (j = 0; j < n_es; j++)
842
 
        if (!strcmp (es[j].encoding, table_encoding))
843
 
          break;
844
 
      if (j >= n_es)
845
 
        {
846
 
          if (n_es >= allocated_es)
847
 
            es = x2nrealloc (es, &allocated_es, sizeof *es);
848
 
          es[n_es++] = (struct encoded_strings) {
849
 
            .encoding = xstrdup (table_encoding),
850
 
            .strings = STRING_ARRAY_INITIALIZER,
851
 
          };
852
 
        }
853
 
      collect_spvlb_strings (table, &es[j].strings);
854
 
    }
855
 
  free (items);
856
 
 
857
 
  for (size_t i = 0; i < n_es; i++)
858
 
    {
859
 
      dump_strings (es[i].encoding, &es[i].strings);
860
 
      free (es[i].encoding);
861
 
      string_array_destroy (&es[i].strings);
862
 
    }
863
 
  free (es);
864
 
 
865
 
  spv_close (spv);
 
734
  struct output_item *root = read_and_filter_spv (argv[1], NULL);
 
735
 
 
736
  struct encoded_strings_table t = { .es = NULL };
 
737
  struct output_iterator iter;
 
738
  OUTPUT_ITEM_FOR_EACH (&iter, root)
 
739
    {
 
740
      const struct output_item *item = iter.cur;
 
741
      if (item->type == OUTPUT_ITEM_TABLE
 
742
          && !item->spv_info->xml_member
 
743
          && item->spv_info->bin_member)
 
744
        collect_strings (item, &t);
 
745
    }
 
746
 
 
747
  for (size_t i = 0; i < t.n; i++)
 
748
    {
 
749
      dump_strings (t.es[i].encoding, &t.es[i].strings);
 
750
      free (t.es[i].encoding);
 
751
      string_array_destroy (&t.es[i].strings);
 
752
    }
 
753
  free (t.es);
 
754
 
 
755
  output_item_unref (root);
866
756
}
867
757
 
868
758
struct command
967
857
  return n_warnings ? EXIT_FAILURE : EXIT_SUCCESS;
968
858
}
969
859
 
970
 
static struct spv_criteria *
 
860
static struct output_criteria *
971
861
get_criteria (void)
972
862
{
973
863
  if (!n_criteria || new_criteria)
976
866
      if (n_criteria >= allocated_criteria)
977
867
        criteria = x2nrealloc (criteria, &allocated_criteria,
978
868
                               sizeof *criteria);
979
 
      criteria[n_criteria++] = (struct spv_criteria) SPV_CRITERIA_INITIALIZER;
 
869
      criteria[n_criteria++]
 
870
        = (struct output_criteria) OUTPUT_CRITERIA_INITIALIZER;
980
871
    }
981
872
 
982
873
  return &criteria[n_criteria - 1];
992
883
  for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
993
884
    {
994
885
      if (!strcmp (arg, "all"))
995
 
        classes = SPV_ALL_CLASSES;
 
886
        classes = OUTPUT_ALL_CLASSES;
996
887
      else if (!strcmp (arg, "help"))
997
888
        {
998
889
          puts (_("The following object classes are supported:"));
999
 
          for (int class = 0; class < SPV_N_CLASSES; class++)
1000
 
            printf ("- %s\n", spv_item_class_to_string (class));
 
890
          for (int class = 0; class < OUTPUT_N_CLASSES; class++)
 
891
            printf ("- %s\n", output_item_class_to_string (class));
1001
892
          exit (0);
1002
893
        }
1003
894
      else
1004
895
        {
1005
 
          int class = spv_item_class_from_string (token);
1006
 
          if (class == SPV_N_CLASSES)
1007
 
            error (1, 0, _("%s: unknown object class (use --select=help "
 
896
          int class = output_item_class_from_string (token);
 
897
          if (class == OUTPUT_N_CLASSES)
 
898
            error (1, 0, _("unknown object class \"%s\" (use --select=help "
1008
899
                           "for help)"), arg);
1009
900
          classes |= 1u << class;
1010
901
        }
1011
902
    }
1012
903
 
1013
 
  struct spv_criteria *c = get_criteria ();
1014
 
  c->classes = invert ? classes ^ SPV_ALL_CLASSES : classes;
 
904
  struct output_criteria *c = get_criteria ();
 
905
  c->classes = invert ? classes ^ OUTPUT_ALL_CLASSES : classes;
1015
906
}
1016
907
 
1017
 
static struct spv_criteria_match *
 
908
static struct output_criteria_match *
1018
909
get_criteria_match (const char **arg)
1019
910
{
1020
 
  struct spv_criteria *c = get_criteria ();
 
911
  struct output_criteria *c = get_criteria ();
1021
912
  if ((*arg)[0] == '^')
1022
913
    {
1023
914
      (*arg)++;
1030
921
static void
1031
922
parse_commands (const char *arg)
1032
923
{
1033
 
  struct spv_criteria_match *cm = get_criteria_match (&arg);
 
924
  struct output_criteria_match *cm = get_criteria_match (&arg);
1034
925
  string_array_parse (&cm->commands, ss_cstr (arg), ss_cstr (","));
1035
926
}
1036
927
 
1037
928
static void
1038
929
parse_subtypes (const char *arg)
1039
930
{
1040
 
  struct spv_criteria_match *cm = get_criteria_match (&arg);
 
931
  struct output_criteria_match *cm = get_criteria_match (&arg);
1041
932
  string_array_parse (&cm->subtypes, ss_cstr (arg), ss_cstr (","));
1042
933
}
1043
934
 
1044
935
static void
1045
936
parse_labels (const char *arg)
1046
937
{
1047
 
  struct spv_criteria_match *cm = get_criteria_match (&arg);
 
938
  struct output_criteria_match *cm = get_criteria_match (&arg);
1048
939
  string_array_parse (&cm->labels, ss_cstr (arg), ss_cstr (","));
1049
940
}
1050
941
 
1051
942
static void
1052
943
parse_instances (char *arg)
1053
944
{
1054
 
  struct spv_criteria *c = get_criteria ();
 
945
  struct output_criteria *c = get_criteria ();
1055
946
  size_t allocated_instances = c->n_instances;
1056
947
 
1057
948
  for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
1068
959
static void
1069
960
parse_nth_commands (char *arg)
1070
961
{
1071
 
  struct spv_criteria *c = get_criteria ();
 
962
  struct output_criteria *c = get_criteria ();
1072
963
  size_t allocated_commands = c->n_commands;
1073
964
 
1074
965
  for (char *token = strtok (arg, ","); token; token = strtok (NULL, ","))
1084
975
static void
1085
976
parse_members (const char *arg)
1086
977
{
1087
 
  struct spv_criteria *cm = get_criteria ();
 
978
  struct output_criteria *cm = get_criteria ();
1088
979
  string_array_parse (&cm->members, ss_cstr (arg), ss_cstr (","));
1089
980
}
1090
981
 
1093
984
{
1094
985
  pivot_table_look_unref (table_look);
1095
986
 
1096
 
  char *error_s = spv_table_look_read (arg, &table_look);
 
987
  char *error_s = pivot_table_look_read (arg, &table_look);
1097
988
  if (error_s)
1098
989
    error (1, 0, "%s", error_s);
1099
990
}